<commit_before>/*************************************************************************
 *
 * Copyright (c) 2008-2010 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef __MDDS_NODE_HXX__
#define __MDDS_NODE_HXX__

#include <iostream>
#include <list>
#include <cassert>

#define USE_INTRUSIVE_PTR 1

#if USE_INTRUSIVE_PTR
#include <boost/intrusive_ptr.hpp>
#else
#include <boost/shared_ptr.hpp>
#endif

namespace mdds {

struct intrusive_ref_base
{
#if USE_INTRUSIVE_PTR
    size_t _refcount;

    intrusive_ref_base() :
        _refcount(0) {}
#endif
    virtual ~intrusive_ref_base() {}
};

#if USE_INTRUSIVE_PTR
inline void intrusive_ptr_add_ref(intrusive_ref_base* p)
{
    ++p->_refcount;
}

inline void intrusive_ptr_release(intrusive_ref_base* p)
{
    --p->_refcount;
    if (!p->_refcount)
        delete p;
}
#endif

#ifdef DEBUG_NODE_BASE
size_t node_instance_count = 0;
#endif

struct node_base;
#if USE_INTRUSIVE_PTR
typedef ::boost::intrusive_ptr<node_base> node_base_ptr;
#else
typedef ::boost::shared_ptr<node_base> node_base_ptr;
#endif

struct node_base : public intrusive_ref_base
{
    static size_t get_instance_count()
    {
#ifdef DEBUG_NODE_BASE
        return node_instance_count;
#else
        return 0;
#endif
    }
    node_base_ptr   parent; /// parent node
    node_base_ptr   left;   /// left child node or previous sibling if it's a leaf node.
    node_base_ptr   right;  /// right child node or next sibling if it's aleaf node.
    bool            is_leaf;

    node_base(bool _is_leaf) :
        intrusive_ref_base(),
        parent(static_cast<node_base*>(NULL)),
        left(static_cast<node_base*>(NULL)),
        right(static_cast<node_base*>(NULL)),
        is_leaf(_is_leaf)
    {
#ifdef DEBUG_NODE_BASE
        ++node_instance_count;
#endif
    }

    /**
     * When copying node, only the stored values should be copied.
     * Connections to the parent, left and right nodes must not be copied.
     */
    node_base(const node_base& r) :
        intrusive_ref_base(),
        parent(static_cast<node_base*>(NULL)),
        left(static_cast<node_base*>(NULL)),
        right(static_cast<node_base*>(NULL)),
        is_leaf(r.is_leaf)
    {
#ifdef DEBUG_NODE_BASE
        ++node_instance_count;
#endif
    }

    /**
     * Like the copy constructor, only the stored values should be copied.
     */
    node_base& operator=(const node_base& r)
    {
        if (this == &r)
            // assignment to self.
            return *this;

        is_leaf = r.is_leaf;
        return *this;
    }

    virtual ~node_base()
    {
#ifdef DEBUG_NODE_BASE
        --node_instance_count;
#endif
    }

    // These methods are specific to concrete class implementation.

    virtual void fill_nonleaf_value(const node_base_ptr& left_node, const node_base_ptr& right_node) = 0;
    virtual node_base* create_new(bool leaf) const = 0;
    virtual node_base* clone() const = 0;
#if UNIT_TEST
    virtual void dump_value() const = 0;
#endif
};

void disconnect_node(node_base* p)
{
    if (!p)
        return;

    p->left.reset();
    p->right.reset();
    p->parent.reset();
}

void disconnect_leaf_nodes(node_base* left_node, node_base* right_node)
{
    if (!left_node || !right_node)
        return;

    // Go through all leaf nodes, and disconnect their links.
    node_base* cur_node = left_node;
    do
    {
        node_base* next_node = cur_node->right.get();
        disconnect_node(cur_node);
        cur_node = next_node;
    }
    while (cur_node != right_node);

    disconnect_node(right_node);
}

template<typename _NodePtr>
void link_nodes(_NodePtr& left, _NodePtr& right)
{
    left->right = right;
    right->left = left;
}

/**
 * Disconnect all non-leaf nodes so that their ref-counted instances will
 * all get destroyed afterwards.
 */
void clear_tree(node_base* node)
{
    if (!node)
        // Nothing to do.
        return;

    if (node->is_leaf)
    {
        node->parent.reset();
        return;
    }

    clear_tree(node->left.get());
    clear_tree(node->right.get());
    disconnect_node(node);
}

template<typename _NodePtr>
_NodePtr make_parent_node(const _NodePtr& node1, const _NodePtr& node2)
{
    _NodePtr parent_node(node1->create_new(false));
    node1->parent = parent_node;
    parent_node->left = node1;
    if (node2)
    {
        node2->parent = parent_node;
        parent_node->right = node2;
    }

    parent_node->fill_nonleaf_value(node1, node2);
    return parent_node;
}

template<typename _NodePtr>
_NodePtr build_tree(const _NodePtr& left_leaf_node)
{
    if (!left_leaf_node)
        // The left leaf node is empty.  Nothing to build.
        return _NodePtr();

    _NodePtr node1, node2;
    node1 = left_leaf_node;

    ::std::list<_NodePtr> node_list;
    while (true)
    {
        node2 = node1->right;
        _NodePtr parent_node = make_parent_node(node1, node2);
        node_list.push_back(parent_node);

        if (!node2 || !node2->right)
            // no more nodes.  Break out of the loop.
            break;

        node1 = node2->right;
    }

    return build_tree_non_leaf(node_list);
}

template<typename _NodePtr>
_NodePtr build_tree_non_leaf(const ::std::list<_NodePtr>& node_list)
{
    size_t node_count = node_list.size();
    if (node_count == 1)
    {
        return node_list.front();
    }
    else if (node_count == 0)
        return _NodePtr();

    ::std::list<_NodePtr> new_node_list;
    _NodePtr node_pair[2];
    typename ::std::list<_NodePtr>::const_iterator itr    = node_list.begin();
    typename ::std::list<_NodePtr>::const_iterator itrEnd = node_list.end();
    for (bool even_itr = false; itr != itrEnd; ++itr, even_itr = !even_itr)
    {
        node_pair[even_itr] = *itr;
        if (even_itr)
        {
            _NodePtr parent_node = make_parent_node(node_pair[0], node_pair[1]);
            node_pair[0].reset();
            node_pair[1].reset();
            new_node_list.push_back(parent_node);
        }
    }

    if (node_pair[0])
    {
        // Un-paired node still needs a parent...
        _NodePtr parent_node = make_parent_node(node_pair[0], _NodePtr());
        node_pair[0].reset();
        node_pair[1].reset();
        new_node_list.push_back(parent_node);
    }

    // Move up one level, and do the same procedure until the root node is reached.
    return build_tree_non_leaf(new_node_list);
}

#ifdef UNIT_TEST
template<typename _NodePtr>
size_t dump_tree_layer(const ::std::list<_NodePtr>& node_list, unsigned int level)
{
    using ::std::cout;
    using ::std::endl;

    if (node_list.empty())
        return 0;

    size_t node_count = node_list.size();

    bool isLeaf = node_list.front()->is_leaf;
    cout << "level " << level << " (" << (isLeaf?"leaf":"non-leaf") << ")" << endl;

    ::std::list<_NodePtr> newList;
    typename ::std::list<_NodePtr>::const_iterator itr = node_list.begin(), itrEnd = node_list.end();
    for (; itr != itrEnd; ++itr)
    {
        const _NodePtr& p = *itr;
        if (!p)
        {
            cout << "(x) ";
            continue;
        }

        p->dump_value();

        if (p->is_leaf)
            continue;

        if (p->left)
        {
            newList.push_back(p->left);
            if (p->right)
                newList.push_back(p->right);
        }
    }
    cout << endl;

    if (!newList.empty())
        node_count += dump_tree_layer(newList, level+1);

    return node_count;
}

template<typename _NodePtr>
size_t dump_tree(const _NodePtr& root_node)
{
    if (!root_node)
        return 0;

    ::std::list<_NodePtr> node_list;
    node_list.push_back(root_node);
    return dump_tree_layer(node_list, 0);
}
#endif

}

#endif
<commit_msg>Remove option to use shared_ptr to ref-count nodes.  Always use intrusive_ptr.<commit_after>/*************************************************************************
 *
 * Copyright (c) 2008-2010 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef __MDDS_NODE_HXX__
#define __MDDS_NODE_HXX__

#include <iostream>
#include <list>
#include <cassert>

#include <boost/intrusive_ptr.hpp>

namespace mdds {

struct intrusive_ref_base
{
    size_t _refcount;

    intrusive_ref_base() :
        _refcount(0) {}

    virtual ~intrusive_ref_base() {}
};

inline void intrusive_ptr_add_ref(intrusive_ref_base* p)
{
    ++p->_refcount;
}

inline void intrusive_ptr_release(intrusive_ref_base* p)
{
    --p->_refcount;
    if (!p->_refcount)
        delete p;
}

#ifdef DEBUG_NODE_BASE
size_t node_instance_count = 0;
#endif

struct node_base;
typedef ::boost::intrusive_ptr<node_base> node_base_ptr;

struct node_base : public intrusive_ref_base
{
    static size_t get_instance_count()
    {
#ifdef DEBUG_NODE_BASE
        return node_instance_count;
#else
        return 0;
#endif
    }
    node_base_ptr   parent; /// parent node
    node_base_ptr   left;   /// left child node or previous sibling if it's a leaf node.
    node_base_ptr   right;  /// right child node or next sibling if it's aleaf node.
    bool            is_leaf;

    node_base(bool _is_leaf) :
        intrusive_ref_base(),
        parent(static_cast<node_base*>(NULL)),
        left(static_cast<node_base*>(NULL)),
        right(static_cast<node_base*>(NULL)),
        is_leaf(_is_leaf)
    {
#ifdef DEBUG_NODE_BASE
        ++node_instance_count;
#endif
    }

    /**
     * When copying node, only the stored values should be copied.
     * Connections to the parent, left and right nodes must not be copied.
     */
    node_base(const node_base& r) :
        intrusive_ref_base(),
        parent(static_cast<node_base*>(NULL)),
        left(static_cast<node_base*>(NULL)),
        right(static_cast<node_base*>(NULL)),
        is_leaf(r.is_leaf)
    {
#ifdef DEBUG_NODE_BASE
        ++node_instance_count;
#endif
    }

    /**
     * Like the copy constructor, only the stored values should be copied.
     */
    node_base& operator=(const node_base& r)
    {
        if (this == &r)
            // assignment to self.
            return *this;

        is_leaf = r.is_leaf;
        return *this;
    }

    virtual ~node_base()
    {
#ifdef DEBUG_NODE_BASE
        --node_instance_count;
#endif
    }

    // These methods are specific to concrete class implementation.

    virtual void fill_nonleaf_value(const node_base_ptr& left_node, const node_base_ptr& right_node) = 0;
    virtual node_base* create_new(bool leaf) const = 0;
    virtual node_base* clone() const = 0;
#if UNIT_TEST
    virtual void dump_value() const = 0;
#endif
};

void disconnect_node(node_base* p)
{
    if (!p)
        return;

    p->left.reset();
    p->right.reset();
    p->parent.reset();
}

void disconnect_leaf_nodes(node_base* left_node, node_base* right_node)
{
    if (!left_node || !right_node)
        return;

    // Go through all leaf nodes, and disconnect their links.
    node_base* cur_node = left_node;
    do
    {
        node_base* next_node = cur_node->right.get();
        disconnect_node(cur_node);
        cur_node = next_node;
    }
    while (cur_node != right_node);

    disconnect_node(right_node);
}

template<typename _NodePtr>
void link_nodes(_NodePtr& left, _NodePtr& right)
{
    left->right = right;
    right->left = left;
}

/**
 * Disconnect all non-leaf nodes so that their ref-counted instances will
 * all get destroyed afterwards.
 */
void clear_tree(node_base* node)
{
    if (!node)
        // Nothing to do.
        return;

    if (node->is_leaf)
    {
        node->parent.reset();
        return;
    }

    clear_tree(node->left.get());
    clear_tree(node->right.get());
    disconnect_node(node);
}

template<typename _NodePtr>
_NodePtr make_parent_node(const _NodePtr& node1, const _NodePtr& node2)
{
    _NodePtr parent_node(node1->create_new(false));
    node1->parent = parent_node;
    parent_node->left = node1;
    if (node2)
    {
        node2->parent = parent_node;
        parent_node->right = node2;
    }

    parent_node->fill_nonleaf_value(node1, node2);
    return parent_node;
}

template<typename _NodePtr>
_NodePtr build_tree(const _NodePtr& left_leaf_node)
{
    if (!left_leaf_node)
        // The left leaf node is empty.  Nothing to build.
        return _NodePtr();

    _NodePtr node1, node2;
    node1 = left_leaf_node;

    ::std::list<_NodePtr> node_list;
    while (true)
    {
        node2 = node1->right;
        _NodePtr parent_node = make_parent_node(node1, node2);
        node_list.push_back(parent_node);

        if (!node2 || !node2->right)
            // no more nodes.  Break out of the loop.
            break;

        node1 = node2->right;
    }

    return build_tree_non_leaf(node_list);
}

template<typename _NodePtr>
_NodePtr build_tree_non_leaf(const ::std::list<_NodePtr>& node_list)
{
    size_t node_count = node_list.size();
    if (node_count == 1)
    {
        return node_list.front();
    }
    else if (node_count == 0)
        return _NodePtr();

    ::std::list<_NodePtr> new_node_list;
    _NodePtr node_pair[2];
    typename ::std::list<_NodePtr>::const_iterator itr    = node_list.begin();
    typename ::std::list<_NodePtr>::const_iterator itrEnd = node_list.end();
    for (bool even_itr = false; itr != itrEnd; ++itr, even_itr = !even_itr)
    {
        node_pair[even_itr] = *itr;
        if (even_itr)
        {
            _NodePtr parent_node = make_parent_node(node_pair[0], node_pair[1]);
            node_pair[0].reset();
            node_pair[1].reset();
            new_node_list.push_back(parent_node);
        }
    }

    if (node_pair[0])
    {
        // Un-paired node still needs a parent...
        _NodePtr parent_node = make_parent_node(node_pair[0], _NodePtr());
        node_pair[0].reset();
        node_pair[1].reset();
        new_node_list.push_back(parent_node);
    }

    // Move up one level, and do the same procedure until the root node is reached.
    return build_tree_non_leaf(new_node_list);
}

#ifdef UNIT_TEST
template<typename _NodePtr>
size_t dump_tree_layer(const ::std::list<_NodePtr>& node_list, unsigned int level)
{
    using ::std::cout;
    using ::std::endl;

    if (node_list.empty())
        return 0;

    size_t node_count = node_list.size();

    bool isLeaf = node_list.front()->is_leaf;
    cout << "level " << level << " (" << (isLeaf?"leaf":"non-leaf") << ")" << endl;

    ::std::list<_NodePtr> newList;
    typename ::std::list<_NodePtr>::const_iterator itr = node_list.begin(), itrEnd = node_list.end();
    for (; itr != itrEnd; ++itr)
    {
        const _NodePtr& p = *itr;
        if (!p)
        {
            cout << "(x) ";
            continue;
        }

        p->dump_value();

        if (p->is_leaf)
            continue;

        if (p->left)
        {
            newList.push_back(p->left);
            if (p->right)
                newList.push_back(p->right);
        }
    }
    cout << endl;

    if (!newList.empty())
        node_count += dump_tree_layer(newList, level+1);

    return node_count;
}

template<typename _NodePtr>
size_t dump_tree(const _NodePtr& root_node)
{
    if (!root_node)
        return 0;

    ::std::list<_NodePtr> node_list;
    node_list.push_back(root_node);
    return dump_tree_layer(node_list, 0);
}
#endif

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "fields.h"
#include <xapian/query.h>

NumericFieldProcessor::NumericFieldProcessor(const std::string &prefix_): prefix(prefix_) {}

Xapian::Query
NumericFieldProcessor::operator()(const std::string &str)
{
	// For negative number, we receive _# and we serialise -#.
	std::string serialise(str.c_str());
	if (serialise.at(0) == '_') serialise.at(0) = '-';
	LOG(this, "Numeric FP %s!!\n", serialise.c_str());
	serialise = serialise_numeric(serialise);
	if (serialise.size() == 0) {
		throw Xapian::QueryParserError("Didn't understand numeric specification '" + str + "'");
	}
	return Xapian::Query(prefix + serialise);
}

BooleanFieldProcessor::BooleanFieldProcessor(const std::string &prefix_): prefix(prefix_) {}

Xapian::Query BooleanFieldProcessor::operator()(const std::string &str)
{
	LOG(this, "Boolean FP!!\n");
	std::string serialise = serialise_bool(str);
	if (serialise.size() == 0) {
		throw Xapian::QueryParserError("Didn't understand bool specification '" + str + "'");
	}
	return Xapian::Query(prefix + serialise);
}

DateFieldProcessor::DateFieldProcessor(const std::string &prefix_): prefix(prefix_) {}

Xapian::Query DateFieldProcessor::operator()(const std::string &str)
{
	std::string serialise(str.c_str());
	if (serialise.at(0) == '_') serialise.at(0) = '-';
	LOG(this, "Date FP %s!!\n", serialise.c_str());
	serialise = serialise_date(serialise);
	if (serialise.size() == 0) {
		throw Xapian::QueryParserError("Didn't understand date specification '" + str + "'");
	}
	return Xapian::Query(prefix + serialise);
}

DateTimeValueRangeProcessor::DateTimeValueRangeProcessor(Xapian::valueno slot_, const std::string &prefix_): valno(slot_), prefix(prefix_) {}

Xapian::valueno
DateTimeValueRangeProcessor::operator()(std::string &begin, std::string &end)
{
	std::string buf;
	LOG(this, "Inside of DateTimeValueRangeProcessor\n");

	// Verify the prefix.
	if (std::string(begin.c_str(), 0, prefix.size()).compare(prefix) == 0) {
		begin.assign(begin.c_str(), prefix.size(), begin.size());
	} else return valno;

	if (begin.size() != 0) {
		std::string serialise = serialise_date(begin);
		printf("Begin: %s End: %s\n", begin.c_str(), end.c_str());
		if (serialise.size() == 0) return Xapian::BAD_VALUENO;
		buf = prefix + serialise;
		begin.assign(buf.c_str(), buf.size());
		LOG(this, "Serialise of begin %s\n", buf.c_str());
	}
	buf = "";

	if (end.size() != 0) {
		std::string serialise = serialise_date(end);
		if (serialise.size() == 0) return Xapian::BAD_VALUENO;
		buf = serialise;
		end.assign(buf.c_str(), buf.size());
		LOG(this, "Serialise of end %s\n", buf.c_str());
	}
	LOG(this, "DateTimeValueRangeProcessor process\n");

	return valno;
}<commit_msg>Fixing Bug in DateTimeValueRangeProcessor<commit_after>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "fields.h"
#include <xapian/query.h>

NumericFieldProcessor::NumericFieldProcessor(const std::string &prefix_): prefix(prefix_) {}

Xapian::Query
NumericFieldProcessor::operator()(const std::string &str)
{
	// For negative number, we receive _# and we serialise -#.
	std::string serialise(str.c_str());
	if (serialise.at(0) == '_') serialise.at(0) = '-';
	LOG(this, "Numeric FP %s!!\n", serialise.c_str());
	serialise = serialise_numeric(serialise);
	if (serialise.size() == 0) {
		throw Xapian::QueryParserError("Didn't understand numeric specification '" + str + "'");
	}
	return Xapian::Query(prefix + serialise);
}

BooleanFieldProcessor::BooleanFieldProcessor(const std::string &prefix_): prefix(prefix_) {}

Xapian::Query BooleanFieldProcessor::operator()(const std::string &str)
{
	LOG(this, "Boolean FP!!\n");
	std::string serialise = serialise_bool(str);
	if (serialise.size() == 0) {
		throw Xapian::QueryParserError("Didn't understand bool specification '" + str + "'");
	}
	return Xapian::Query(prefix + serialise);
}

DateFieldProcessor::DateFieldProcessor(const std::string &prefix_): prefix(prefix_) {}

Xapian::Query DateFieldProcessor::operator()(const std::string &str)
{
	std::string serialise(str.c_str());
	if (serialise.at(0) == '_') serialise.at(0) = '-';
	LOG(this, "Date FP %s!!\n", serialise.c_str());
	serialise = serialise_date(serialise);
	if (serialise.size() == 0) {
		throw Xapian::QueryParserError("Didn't understand date specification '" + str + "'");
	}
	return Xapian::Query(prefix + serialise);
}

DateTimeValueRangeProcessor::DateTimeValueRangeProcessor(Xapian::valueno slot_, const std::string &prefix_): valno(slot_), prefix(prefix_) {}

Xapian::valueno
DateTimeValueRangeProcessor::operator()(std::string &begin, std::string &end)
{
	std::string buf;
	LOG(this, "Inside of DateTimeValueRangeProcessor\n");

	// Verify the prefix.
	if (std::string(begin.c_str(), 0, prefix.size()).compare(prefix) == 0) {
		begin.assign(begin.c_str(), prefix.size(), begin.size());
	} else return valno;

	if (begin.size() != 0) {
		std::string serialise = serialise_date(begin);
		printf("Begin: %s End: %s\n", begin.c_str(), end.c_str());
		if (serialise.size() == 0) return Xapian::BAD_VALUENO;
		buf = serialise;
		begin.assign(buf.c_str(), buf.size());
		LOG(this, "Serialise of begin %s\n", buf.c_str());
	}
	buf = "";

	if (end.size() != 0) {
		std::string serialise = serialise_date(end);
		if (serialise.size() == 0) return Xapian::BAD_VALUENO;
		buf = serialise;
		end.assign(buf.c_str(), buf.size());
		LOG(this, "Serialise of end %s\n", buf.c_str());
	}
	LOG(this, "DateTimeValueRangeProcessor process\n");

	return valno;
}<|endoftext|>


<commit_before>//#include "State_Menu.h"
#include "../Globals.h"
//#include "../GameEngine.h"
//#include "../Graphics/GraphicEngine.h"
#include "../InputMap.h"
#include "MenuActions.h"

void State_Menu::Init()
{
	//just a test
	ALLEGRO_BITMAP *menu = nullptr;
	menu = al_load_bitmap("assets/img/UI/Menu.jpg");

	std::vector<ALLEGRO_BITMAP *> menu_bitmap { menu };

	graphicEngine->DefineUI_Element_Graphic("class Menu", menu_bitmap);

	//we need to fix this class UI_element * to use it for more than 1 object tho :D

	ALLEGRO_BITMAP *default = nullptr;
	default = al_load_bitmap("assets/img/UI/button.png");
	ALLEGRO_BITMAP *hover = nullptr;
	hover = al_load_bitmap("assets/img/UI/button_highlighted.png");
	ALLEGRO_BITMAP *clicked = nullptr;
	clicked = al_load_bitmap("assets/img/UI/button_clicked.png");

	std::vector<ALLEGRO_BITMAP *> button_bitmaps{ default, hover, clicked };

	graphicEngine->DefineUI_Element_Graphic("class Button", button_bitmaps); //temporary solution

	//end of the test

	mainMenu = new Menu("Main Menu");
	optionsMenu = new Menu("Options");
	pauseMenu = new Menu("Surrender?");
	waveMenu = new Menu("Next Wave");

	mainMenu->AddButton("Start Game", MenuActions::StartGame);
	mainMenu->AddButton("Options", MenuActions::Options);
	mainMenu->AddButton("Credits", MenuActions::Credits);
	mainMenu->AddButton("Exit", MenuActions::Exit);

	optionsMenu->AddButton("Resolution", MenuActions::Resolution);
	optionsMenu->AddButton("Sound", MenuActions::Sound);
	optionsMenu->AddButton("Back", MenuActions::Back);

	pauseMenu->AddButton("Yesh", MenuActions::Yesh);
	pauseMenu->AddButton("Nah", MenuActions::Nah);

	waveMenu->AddButton("Continue", MenuActions::Continue);
	waveMenu->AddButton("Surrender", MenuActions::Surrender);

	menuList = {mainMenu, optionsMenu, pauseMenu, waveMenu};
	SwitchToMenu("Main Menu");
}

void State_Menu::SwitchToMenu(string newMenu)
{
	for(auto menuit : menuList)
	{
		if(menuit->menuTitle == newMenu)
			CurrentMenu = menuit;	//???
	}

}

void State_Menu::Cleanup()
{
	while (!menuList.empty())
	{
		menuList.back()->Cleanup();
		menuList.pop_back();
	}
}

void State_Menu::Pause()
{
	//???
}
void State_Menu::Resume()
{
	//???
}

void State_Menu::HandleEvents()
{

}

void State_Menu::Update()		//	To do: handling input/UseFunction();
{
	for (int i = 0; i < CurrentMenu->buttons.size(); i++)
	{
		if ((mouseX >= (CurrentMenu->buttons[i]->x - CurrentMenu->buttons[i]->width / 2)) &&
			(mouseX <= (CurrentMenu->buttons[i]->x + CurrentMenu->buttons[i]->width / 2)) &&
			(mouseY >= (CurrentMenu->buttons[i]->y - CurrentMenu->buttons[i]->height / 2)) &&
			(mouseY <= (CurrentMenu->buttons[i]->y + CurrentMenu->buttons[i]->height / 2)))
		{
			CurrentMenu->buttons[i]->highlighted = true;
			graphicEngine->RequestUI_Element_Graphic(CurrentMenu->buttons[i], 2);
			if (CurrentMenu->MarkedButton == NULL) CurrentMenu->MarkedButton = CurrentMenu->buttons[i];
			break;
		}
		else
		{
			CurrentMenu->buttons[i]->highlighted = false;
			if (CurrentMenu->MarkedButton != NULL) CurrentMenu->MarkedButton = NULL;
			if (CurrentMenu->buttons[i]->clicked) CurrentMenu->buttons[i]->clicked = false;
		}
	}
	if (mouse[LMB])
	{
		if (CurrentMenu->MarkedButton != NULL && CurrentMenu->MarkedButton->highlighted) CurrentMenu->MarkedButton->clicked = true;
	}
	if (!mouse[LMB] && CurrentMenu->MarkedButton != NULL && CurrentMenu->MarkedButton->clicked)
	{
		cout << "Action!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl;
		CurrentMenu->MarkedButton->UseFunction();
		CurrentMenu->MarkedButton->clicked = false;
	}/*
	if (CurrentMenu->MarkedButton != NULL)		// Small but fancy debug!
	{
		if (CurrentMenu->MarkedButton->clicked) cout << "Clicked!" << endl;
		else cout << "Highlighted!" << endl;
	}
	else cout << "---" << endl;*/
}

void State_Menu::Render()
{
	//graphicEngine->CreateGraphicInstance(??, ??)
}<commit_msg>Buttons are dehighlighting now, but still are apprearing completly randomly O.o<commit_after>//#include "State_Menu.h"
#include "../Globals.h"
//#include "../GameEngine.h"
//#include "../Graphics/GraphicEngine.h"
#include "../InputMap.h"
#include "MenuActions.h"

void State_Menu::Init()
{
	//just a test
	ALLEGRO_BITMAP *menu = nullptr;
	menu = al_load_bitmap("assets/img/UI/Menu.jpg");

	std::vector<ALLEGRO_BITMAP *> menu_bitmap { menu };

	graphicEngine->DefineUI_Element_Graphic("class Menu", menu_bitmap);

	//we need to fix this class UI_element * to use it for more than 1 object tho :D

	ALLEGRO_BITMAP *default = nullptr;
	default = al_load_bitmap("assets/img/UI/button.png");
	ALLEGRO_BITMAP *hover = nullptr;
	hover = al_load_bitmap("assets/img/UI/button_highlighted.png");
	ALLEGRO_BITMAP *clicked = nullptr;
	clicked = al_load_bitmap("assets/img/UI/button_clicked.png");

	std::vector<ALLEGRO_BITMAP *> button_bitmaps{ default, hover, clicked };

	graphicEngine->DefineUI_Element_Graphic("class Button", button_bitmaps); //temporary solution

	//end of the test

	mainMenu = new Menu("Main Menu");
	optionsMenu = new Menu("Options");
	pauseMenu = new Menu("Surrender?");
	waveMenu = new Menu("Next Wave");

	mainMenu->AddButton("Start Game", MenuActions::StartGame);
	mainMenu->AddButton("Options", MenuActions::Options);
	mainMenu->AddButton("Credits", MenuActions::Credits);
	mainMenu->AddButton("Exit", MenuActions::Exit);

	//optionsMenu->AddButton("Resolution", MenuActions::Resolution);
	//optionsMenu->AddButton("Sound", MenuActions::Sound);
	//optionsMenu->AddButton("Back", MenuActions::Back);

	//pauseMenu->AddButton("Yesh", MenuActions::Yesh);
	//pauseMenu->AddButton("Nah", MenuActions::Nah);

	//waveMenu->AddButton("Continue", MenuActions::Continue);
	//waveMenu->AddButton("Surrender", MenuActions::Surrender);

	menuList = {mainMenu, optionsMenu, pauseMenu, waveMenu};
	SwitchToMenu("Main Menu");
}

void State_Menu::SwitchToMenu(string newMenu)
{
	for(auto menuit : menuList)
	{
		if(menuit->menuTitle == newMenu)
			CurrentMenu = menuit;	//???
	}

}

void State_Menu::Cleanup()
{
	while (!menuList.empty())
	{
		menuList.back()->Cleanup();
		menuList.pop_back();
	}
}

void State_Menu::Pause()
{
	//???
}
void State_Menu::Resume()
{
	//???
}

void State_Menu::HandleEvents()
{

}

void State_Menu::Update()		//	To do: handling input/UseFunction();
{
	for (int i = 0; i < CurrentMenu->buttons.size(); i++)
	{
		if ((mouseX >= (CurrentMenu->buttons[i]->x - CurrentMenu->buttons[i]->width / 2)) &&
			(mouseX <= (CurrentMenu->buttons[i]->x + CurrentMenu->buttons[i]->width / 2)) &&
			(mouseY >= (CurrentMenu->buttons[i]->y - CurrentMenu->buttons[i]->height / 2)) &&
			(mouseY <= (CurrentMenu->buttons[i]->y + CurrentMenu->buttons[i]->height / 2)))
		{
			CurrentMenu->buttons[i]->highlighted = true;
			graphicEngine->RequestUI_Element_Graphic(CurrentMenu->buttons[i], 2);
			if (CurrentMenu->MarkedButton == NULL) CurrentMenu->MarkedButton = CurrentMenu->buttons[i];
			break;
		}
		else
		{
			CurrentMenu->buttons[i]->highlighted = false;
			graphicEngine->RequestUI_Element_Graphic(CurrentMenu->buttons[i], 0);
			if (CurrentMenu->MarkedButton != NULL) CurrentMenu->MarkedButton = NULL;
			if (CurrentMenu->buttons[i]->clicked) CurrentMenu->buttons[i]->clicked = false;
		}
	}
	if (mouse[LMB])
	{
		if (CurrentMenu->MarkedButton != NULL && CurrentMenu->MarkedButton->highlighted) CurrentMenu->MarkedButton->clicked = true;
	}
	if (!mouse[LMB] && CurrentMenu->MarkedButton != NULL && CurrentMenu->MarkedButton->clicked)
	{
		cout << "Action!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl;
		CurrentMenu->MarkedButton->UseFunction();
		CurrentMenu->MarkedButton->clicked = false;
	}/*
	if (CurrentMenu->MarkedButton != NULL)		// Small but fancy debug!
	{
		if (CurrentMenu->MarkedButton->clicked) cout << "Clicked!" << endl;
		else cout << "Highlighted!" << endl;
	}
	else cout << "---" << endl;*/
}

void State_Menu::Render()
{
	//graphicEngine->CreateGraphicInstance(??, ??)
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2019-2020 Fastly, Inc., Toru Maesaka, Goro Fuji
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <memory>
#include <vector>
#include <algorithm>
#include <bcc/BPF.h>
extern "C" {
#include <unistd.h>
#include <stdarg.h>
#include <sys/time.h>
#include "h2o/memory.h"
#include "h2o/version.h"
}
#include "h2olog.h"

#define POLL_TIMEOUT (1000)
#define PERF_BUFFER_PAGE_COUNT 256

static void usage(void)
{
    printf(R"(h2olog (h2o v%s)
Usage: h2olog -p PID
Optional arguments:
    -d Print debugging information (-dd shows more)
    -h Print this help and exit
    -l Print the list of available tracepoints and exit
    -H Trace HTTP requests and responses in varnishlog-like format
    -s RESPONSE_HEADER_NAME A response header name to show, e.g. "content-type"
    -t TRACEPOINT A tracepoint, or fully-qualified probe name, to show, e.g. "quicly:accept"
    -r Run without dropping root privilege
    -w Path to write the output (default: stdout)

Examples:
    h2olog -p -H $(pgrep -o $h2o)
    h2olog -p $(pgrep -o h2o) -t quicly:accept -t quicly:free
    h2olog -p $(pgrep -o h2o) -t h2o:send_response_header -t h2o:h3s_accept -t h2o:h3s_destroy -s alt-svc
)",
           H2O_VERSION);
    return;
}

static void make_timestamp(char *buf, size_t buf_len)
{
    time_t t = time(NULL);
    struct tm tms;
    localtime_r(&t, &tms);
    const char *iso8601format = "%FT%TZ";
    strftime(buf, buf_len, iso8601format, &tms);
}

static void infof(const char *fmt, ...) __attribute__((format(printf, 1, 2)));

static void infof(const char *fmt, ...)
{
    char buf[1024];
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);

    char timestamp[128];
    make_timestamp(timestamp, sizeof(timestamp));

    fprintf(stderr, "%s %s\n", timestamp, buf);
}

uint64_t h2o_tracer::time_milliseconds()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

void h2o_tracer::show_event_per_sec(time_t *t0)
{
    time_t t1 = time(NULL);
    int64_t d = t1 - *t0;
    if (d > 10) {
        uint64_t c = stats_.num_events / d;
        if (c > 0) {
            if (stats_.num_lost > 0) {
                infof("%20" PRIu64 " events/s (possibly lost %" PRIu64 " events)", c, stats_.num_lost);
                stats_.num_lost = 0;
            } else {
                infof("%20" PRIu64 " events/s", c);
            }
            stats_.num_events = 0;
        }
        *t0 = t1;
    }
}

static void show_process(pid_t pid)
{
    char cmdline[256];
    char proc_file[256];
    snprintf(proc_file, sizeof(proc_file), "/proc/%d/cmdline", pid);
    FILE *f = fopen(proc_file, "r");
    if (f == nullptr) {
        fprintf(stderr, "Error: failed to open %s: %s\n", proc_file, strerror(errno));
        exit(EXIT_FAILURE);
    }
    size_t nread = fread(cmdline, 1, sizeof(cmdline), f);
    fclose(f);
    if (nread == 0) {
        fprintf(stderr, "Error: failed to read from %s: %s\n", proc_file, strerror(errno));
        exit(EXIT_FAILURE);
    }
    nread--; // skip trailing nul
    for (size_t i = 0; i < nread; i++) {
        if (cmdline[i] == '\0') {
            cmdline[i] = ' ';
        }
    }
    infof("Attaching pid=%d (%s)", pid, cmdline);
}

static void drop_root_privilege(void)
{
    if (getuid() == 0) {
        const char *sudo_gid = getenv("SUDO_GID");
        if (sudo_gid == NULL) {
            fprintf(stderr, "Error: the SUDO_GID environment variable is not set\n");
            exit(EXIT_FAILURE);
        }
        errno = 0;
        gid_t gid = (gid_t)strtol(sudo_gid, NULL, 10);
        if (errno != 0) {
            fprintf(stderr, "Error: failed to parse SUDO_GID\n");
            exit(EXIT_FAILURE);
        }
        if (setgid(gid) != 0) {
            perror("Error: setgid(2) failed");
            exit(EXIT_FAILURE);
        }
        const char *sudo_uid = getenv("SUDO_UID");
        if (sudo_uid == NULL) {
            fprintf(stderr, "Error: the SUDO_UID environment variable is not set\n");
            exit(EXIT_FAILURE);
        }
        errno = 0;
        uid_t uid = (uid_t)strtol(sudo_uid, NULL, 10);
        if (errno != 0) {
            fprintf(stderr, "Error: failed to parse SUDO_UID\n");
            exit(EXIT_FAILURE);
        }
        if (setuid(uid) != 0) {
            perror("Error: setuid(2) failed");
            exit(EXIT_FAILURE);
        }
    }
}

static std::string join_str(const std::string &sep, const std::vector<std::string> &strs)
{
    std::string s;
    for (auto iter = strs.cbegin(); iter != strs.cend(); ++iter) {
        if (iter != strs.cbegin()) {
            s += sep;
        }
        s += *iter;
    }
    return s;
}

static std::string generate_header_filter_cflag(const std::vector<std::string> &tokens)
{
    std::vector<std::string> conditions;

    for (auto &token : tokens) {
        char buf[256];
        snprintf(buf, sizeof(buf), "/* %s */ (slen) == %zu", token.c_str(), token.size());
        std::vector<std::string> exprs = {buf};

        for (size_t i = 0; i < token.size(); ++i) {
            snprintf(buf, sizeof(buf), "(s)[%zu] == '%c'", i, token[i]);
            exprs.push_back(buf);
        }
        conditions.push_back("(" + join_str(" && ", exprs) + ")");
    }

    std::string cflag("-DCHECK_ALLOWED_RES_HEADER_NAME(s,slen)=(");
    cflag += join_str(" || ", conditions);
    cflag += ")";
    return cflag;
}

static std::string make_pid_cflag(const char *macro_name, pid_t pid)
{
    char buf[256];
    snprintf(buf, sizeof(buf), "-D%s=%d", macro_name, pid);
    return std::string(buf);
}

static void event_cb(void *context, void *data, int len)
{
    h2o_tracer *tracer = (h2o_tracer *)context;
    tracer->handle_event(data, len);
}

static void lost_cb(void *context, uint64_t lost)
{
    h2o_tracer *tracer = (h2o_tracer *)context;
    tracer->handle_lost(lost);
}

int main(int argc, char **argv)
{
    std::unique_ptr<h2o_tracer> tracer;
    if (argc > 1 && strcmp(argv[1], "quic") == 0) {
        fprintf(stderr, "warning: 'quic' mode is deprecated.\n");
        tracer.reset(create_raw_tracer());
        --argc;
        ++argv;
    } else {
        tracer.reset(create_http_tracer());
    }

    const std::vector<h2o_tracer::usdt> available_usdts = tracer->usdt_probes();

    int debug = 0;
    int preserve_root = 0;
    FILE *outfp = stdout;
    std::vector<h2o_tracer::usdt> selected_usdts;
    std::vector<std::string> response_header_filters;
    int c;
    pid_t h2o_pid = -1;
    while ((c = getopt(argc, argv, "hdrlp:t:s:w:")) != -1) {
        switch (c) {
        case 'H':
            tracer.reset(create_http_tracer());
            break;
        case 'p':
            h2o_pid = atoi(optarg);
            break;
        case 't': {
            auto found = std::find_if(available_usdts.cbegin(), available_usdts.cend(),
                                      [](const h2o_tracer::usdt &usdt) { return optarg == usdt.fully_qualified_name(); });
            if (found == available_usdts.cend()) {
                fprintf(stderr, "No such tracepoint: %s\n", optarg);
                exit(EXIT_FAILURE);
            }
            selected_usdts.push_back(*found);
            break;
        }
        case 's':
            response_header_filters.push_back(optarg);
            break;
        case 'w':
            if ((outfp = fopen(optarg, "w")) == nullptr) {
                fprintf(stderr, "Error: failed to open %s: %s", optarg, strerror(errno));
                exit(EXIT_FAILURE);
            }
            break;
        case 'd':
            debug++;
            break;
        case 'l':
            for (const auto &usdt : available_usdts) {
                printf("%s\n", usdt.fully_qualified_name().c_str());
            }
            exit(EXIT_SUCCESS);
            break;
        case 'r':
            preserve_root = 1;
            break;
        case 'h':
            usage();
            exit(EXIT_SUCCESS);
        default:
            usage();
            exit(EXIT_FAILURE);
        }
    }

    if (argc > optind) {
        fprintf(stderr, "Error: too many aruments\n");
        usage();
        exit(EXIT_FAILURE);
    }

    if (h2o_pid == -1) {
        fprintf(stderr, "Error: -p option is missing\n");
        usage();
        exit(EXIT_FAILURE);
    }

    if (geteuid() != 0) {
        fprintf(stderr, "Error: root privilege is required\n");
        exit(EXIT_FAILURE);
    }

    tracer->init(outfp);

    std::vector<std::string> cflags({
        make_pid_cflag("H2OLOG_H2O_PID", h2o_pid),
    });

    if (!response_header_filters.empty()) {
        cflags.push_back(generate_header_filter_cflag(response_header_filters));
    }

    if (selected_usdts.empty()) {
        selected_usdts = available_usdts;
    }

    if (debug >= 2) {
        fprintf(stderr, "selected_usdts=");
        for (auto iter = selected_usdts.cbegin(); iter != selected_usdts.cend(); iter++) {
            if (iter != selected_usdts.cbegin()) {
                fprintf(stderr, ",");
            }
            fprintf(stderr, "%s", iter->fully_qualified_name().c_str());
        }
        fprintf(stderr, "\n");
        fprintf(stderr, "cflags=");
        for (size_t i = 0; i < cflags.size(); i++) {
            if (i > 0) {
                fprintf(stderr, " ");
            }
            fprintf(stderr, "%s", cflags[i].c_str());
        }
        fprintf(stderr, "\n");
        fprintf(stderr, "<BPF>\n%s\n</BPF>\n", tracer->bpf_text().c_str());
    }

    ebpf::BPF *bpf = new ebpf::BPF();
    std::vector<ebpf::USDT> probes;

    for (const auto &usdt : selected_usdts) {
        probes.push_back(ebpf::USDT(h2o_pid, usdt.provider, usdt.name, usdt.probe_func));
    }

    ebpf::StatusTuple ret = bpf->init(tracer->bpf_text(), cflags, probes);
    if (ret.code() != 0) {
        fprintf(stderr, "Error: init: %s\n", ret.msg().c_str());
        return EXIT_FAILURE;
    }

    bpf->attach_tracepoint("sched:sched_process_exit", "trace_sched_process_exit");

    for (auto &probe : probes) {
        ret = bpf->attach_usdt(probe);
        if (ret.code() != 0) {
            fprintf(stderr, "Error: attach_usdt: %s\n", ret.msg().c_str());
            return EXIT_FAILURE;
        }
    }

    ret = bpf->open_perf_buffer("events", event_cb, lost_cb, tracer.get(), PERF_BUFFER_PAGE_COUNT);
    if (ret.code() != 0) {
        fprintf(stderr, "Error: open_perf_buffer: %s\n", ret.msg().c_str());
        return EXIT_FAILURE;
    }

    if (debug) {
        show_process(h2o_pid);
    }
    if (!preserve_root) {
        drop_root_privilege();
    }

    ebpf::BPFPerfBuffer *perf_buffer = bpf->get_perf_buffer("events");
    if (perf_buffer) {
        time_t t0 = time(NULL);

        while (true) {
            perf_buffer->poll(POLL_TIMEOUT);
            tracer->flush();

            if (debug) {
                tracer->show_event_per_sec(&t0);
            }
        }
    }

    fprintf(stderr, "Error: failed to get_perf_buffer()\n");
    return EXIT_FAILURE;
}
<commit_msg>Update src/h2olog/h2olog.cc<commit_after>/*
 * Copyright (c) 2019-2020 Fastly, Inc., Toru Maesaka, Goro Fuji
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <memory>
#include <vector>
#include <algorithm>
#include <bcc/BPF.h>
extern "C" {
#include <unistd.h>
#include <stdarg.h>
#include <sys/time.h>
#include "h2o/memory.h"
#include "h2o/version.h"
}
#include "h2olog.h"

#define POLL_TIMEOUT (1000)
#define PERF_BUFFER_PAGE_COUNT 256

static void usage(void)
{
    printf(R"(h2olog (h2o v%s)
Usage: h2olog -p PID
Optional arguments:
    -d Print debugging information (-dd shows more)
    -h Print this help and exit
    -l Print the list of available tracepoints and exit
    -H Trace HTTP requests and responses in varnishlog-like format
    -s RESPONSE_HEADER_NAME A response header name to show, e.g. "content-type"
    -t TRACEPOINT A tracepoint, or fully-qualified probe name, to show, e.g. "quicly:accept"
    -r Run without dropping root privilege
    -w Path to write the output (default: stdout)

Examples:
    h2olog -p -H $(pgrep -o h2o)
    h2olog -p $(pgrep -o h2o) -t quicly:accept -t quicly:free
    h2olog -p $(pgrep -o h2o) -t h2o:send_response_header -t h2o:h3s_accept -t h2o:h3s_destroy -s alt-svc
)",
           H2O_VERSION);
    return;
}

static void make_timestamp(char *buf, size_t buf_len)
{
    time_t t = time(NULL);
    struct tm tms;
    localtime_r(&t, &tms);
    const char *iso8601format = "%FT%TZ";
    strftime(buf, buf_len, iso8601format, &tms);
}

static void infof(const char *fmt, ...) __attribute__((format(printf, 1, 2)));

static void infof(const char *fmt, ...)
{
    char buf[1024];
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);

    char timestamp[128];
    make_timestamp(timestamp, sizeof(timestamp));

    fprintf(stderr, "%s %s\n", timestamp, buf);
}

uint64_t h2o_tracer::time_milliseconds()
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

void h2o_tracer::show_event_per_sec(time_t *t0)
{
    time_t t1 = time(NULL);
    int64_t d = t1 - *t0;
    if (d > 10) {
        uint64_t c = stats_.num_events / d;
        if (c > 0) {
            if (stats_.num_lost > 0) {
                infof("%20" PRIu64 " events/s (possibly lost %" PRIu64 " events)", c, stats_.num_lost);
                stats_.num_lost = 0;
            } else {
                infof("%20" PRIu64 " events/s", c);
            }
            stats_.num_events = 0;
        }
        *t0 = t1;
    }
}

static void show_process(pid_t pid)
{
    char cmdline[256];
    char proc_file[256];
    snprintf(proc_file, sizeof(proc_file), "/proc/%d/cmdline", pid);
    FILE *f = fopen(proc_file, "r");
    if (f == nullptr) {
        fprintf(stderr, "Error: failed to open %s: %s\n", proc_file, strerror(errno));
        exit(EXIT_FAILURE);
    }
    size_t nread = fread(cmdline, 1, sizeof(cmdline), f);
    fclose(f);
    if (nread == 0) {
        fprintf(stderr, "Error: failed to read from %s: %s\n", proc_file, strerror(errno));
        exit(EXIT_FAILURE);
    }
    nread--; // skip trailing nul
    for (size_t i = 0; i < nread; i++) {
        if (cmdline[i] == '\0') {
            cmdline[i] = ' ';
        }
    }
    infof("Attaching pid=%d (%s)", pid, cmdline);
}

static void drop_root_privilege(void)
{
    if (getuid() == 0) {
        const char *sudo_gid = getenv("SUDO_GID");
        if (sudo_gid == NULL) {
            fprintf(stderr, "Error: the SUDO_GID environment variable is not set\n");
            exit(EXIT_FAILURE);
        }
        errno = 0;
        gid_t gid = (gid_t)strtol(sudo_gid, NULL, 10);
        if (errno != 0) {
            fprintf(stderr, "Error: failed to parse SUDO_GID\n");
            exit(EXIT_FAILURE);
        }
        if (setgid(gid) != 0) {
            perror("Error: setgid(2) failed");
            exit(EXIT_FAILURE);
        }
        const char *sudo_uid = getenv("SUDO_UID");
        if (sudo_uid == NULL) {
            fprintf(stderr, "Error: the SUDO_UID environment variable is not set\n");
            exit(EXIT_FAILURE);
        }
        errno = 0;
        uid_t uid = (uid_t)strtol(sudo_uid, NULL, 10);
        if (errno != 0) {
            fprintf(stderr, "Error: failed to parse SUDO_UID\n");
            exit(EXIT_FAILURE);
        }
        if (setuid(uid) != 0) {
            perror("Error: setuid(2) failed");
            exit(EXIT_FAILURE);
        }
    }
}

static std::string join_str(const std::string &sep, const std::vector<std::string> &strs)
{
    std::string s;
    for (auto iter = strs.cbegin(); iter != strs.cend(); ++iter) {
        if (iter != strs.cbegin()) {
            s += sep;
        }
        s += *iter;
    }
    return s;
}

static std::string generate_header_filter_cflag(const std::vector<std::string> &tokens)
{
    std::vector<std::string> conditions;

    for (auto &token : tokens) {
        char buf[256];
        snprintf(buf, sizeof(buf), "/* %s */ (slen) == %zu", token.c_str(), token.size());
        std::vector<std::string> exprs = {buf};

        for (size_t i = 0; i < token.size(); ++i) {
            snprintf(buf, sizeof(buf), "(s)[%zu] == '%c'", i, token[i]);
            exprs.push_back(buf);
        }
        conditions.push_back("(" + join_str(" && ", exprs) + ")");
    }

    std::string cflag("-DCHECK_ALLOWED_RES_HEADER_NAME(s,slen)=(");
    cflag += join_str(" || ", conditions);
    cflag += ")";
    return cflag;
}

static std::string make_pid_cflag(const char *macro_name, pid_t pid)
{
    char buf[256];
    snprintf(buf, sizeof(buf), "-D%s=%d", macro_name, pid);
    return std::string(buf);
}

static void event_cb(void *context, void *data, int len)
{
    h2o_tracer *tracer = (h2o_tracer *)context;
    tracer->handle_event(data, len);
}

static void lost_cb(void *context, uint64_t lost)
{
    h2o_tracer *tracer = (h2o_tracer *)context;
    tracer->handle_lost(lost);
}

int main(int argc, char **argv)
{
    std::unique_ptr<h2o_tracer> tracer;
    if (argc > 1 && strcmp(argv[1], "quic") == 0) {
        fprintf(stderr, "warning: 'quic' mode is deprecated.\n");
        tracer.reset(create_raw_tracer());
        --argc;
        ++argv;
    } else {
        tracer.reset(create_http_tracer());
    }

    const std::vector<h2o_tracer::usdt> available_usdts = tracer->usdt_probes();

    int debug = 0;
    int preserve_root = 0;
    FILE *outfp = stdout;
    std::vector<h2o_tracer::usdt> selected_usdts;
    std::vector<std::string> response_header_filters;
    int c;
    pid_t h2o_pid = -1;
    while ((c = getopt(argc, argv, "hdrlp:t:s:w:")) != -1) {
        switch (c) {
        case 'H':
            tracer.reset(create_http_tracer());
            break;
        case 'p':
            h2o_pid = atoi(optarg);
            break;
        case 't': {
            auto found = std::find_if(available_usdts.cbegin(), available_usdts.cend(),
                                      [](const h2o_tracer::usdt &usdt) { return optarg == usdt.fully_qualified_name(); });
            if (found == available_usdts.cend()) {
                fprintf(stderr, "No such tracepoint: %s\n", optarg);
                exit(EXIT_FAILURE);
            }
            selected_usdts.push_back(*found);
            break;
        }
        case 's':
            response_header_filters.push_back(optarg);
            break;
        case 'w':
            if ((outfp = fopen(optarg, "w")) == nullptr) {
                fprintf(stderr, "Error: failed to open %s: %s", optarg, strerror(errno));
                exit(EXIT_FAILURE);
            }
            break;
        case 'd':
            debug++;
            break;
        case 'l':
            for (const auto &usdt : available_usdts) {
                printf("%s\n", usdt.fully_qualified_name().c_str());
            }
            exit(EXIT_SUCCESS);
            break;
        case 'r':
            preserve_root = 1;
            break;
        case 'h':
            usage();
            exit(EXIT_SUCCESS);
        default:
            usage();
            exit(EXIT_FAILURE);
        }
    }

    if (argc > optind) {
        fprintf(stderr, "Error: too many aruments\n");
        usage();
        exit(EXIT_FAILURE);
    }

    if (h2o_pid == -1) {
        fprintf(stderr, "Error: -p option is missing\n");
        usage();
        exit(EXIT_FAILURE);
    }

    if (geteuid() != 0) {
        fprintf(stderr, "Error: root privilege is required\n");
        exit(EXIT_FAILURE);
    }

    tracer->init(outfp);

    std::vector<std::string> cflags({
        make_pid_cflag("H2OLOG_H2O_PID", h2o_pid),
    });

    if (!response_header_filters.empty()) {
        cflags.push_back(generate_header_filter_cflag(response_header_filters));
    }

    if (selected_usdts.empty()) {
        selected_usdts = available_usdts;
    }

    if (debug >= 2) {
        fprintf(stderr, "selected_usdts=");
        for (auto iter = selected_usdts.cbegin(); iter != selected_usdts.cend(); iter++) {
            if (iter != selected_usdts.cbegin()) {
                fprintf(stderr, ",");
            }
            fprintf(stderr, "%s", iter->fully_qualified_name().c_str());
        }
        fprintf(stderr, "\n");
        fprintf(stderr, "cflags=");
        for (size_t i = 0; i < cflags.size(); i++) {
            if (i > 0) {
                fprintf(stderr, " ");
            }
            fprintf(stderr, "%s", cflags[i].c_str());
        }
        fprintf(stderr, "\n");
        fprintf(stderr, "<BPF>\n%s\n</BPF>\n", tracer->bpf_text().c_str());
    }

    ebpf::BPF *bpf = new ebpf::BPF();
    std::vector<ebpf::USDT> probes;

    for (const auto &usdt : selected_usdts) {
        probes.push_back(ebpf::USDT(h2o_pid, usdt.provider, usdt.name, usdt.probe_func));
    }

    ebpf::StatusTuple ret = bpf->init(tracer->bpf_text(), cflags, probes);
    if (ret.code() != 0) {
        fprintf(stderr, "Error: init: %s\n", ret.msg().c_str());
        return EXIT_FAILURE;
    }

    bpf->attach_tracepoint("sched:sched_process_exit", "trace_sched_process_exit");

    for (auto &probe : probes) {
        ret = bpf->attach_usdt(probe);
        if (ret.code() != 0) {
            fprintf(stderr, "Error: attach_usdt: %s\n", ret.msg().c_str());
            return EXIT_FAILURE;
        }
    }

    ret = bpf->open_perf_buffer("events", event_cb, lost_cb, tracer.get(), PERF_BUFFER_PAGE_COUNT);
    if (ret.code() != 0) {
        fprintf(stderr, "Error: open_perf_buffer: %s\n", ret.msg().c_str());
        return EXIT_FAILURE;
    }

    if (debug) {
        show_process(h2o_pid);
    }
    if (!preserve_root) {
        drop_root_privilege();
    }

    ebpf::BPFPerfBuffer *perf_buffer = bpf->get_perf_buffer("events");
    if (perf_buffer) {
        time_t t0 = time(NULL);

        while (true) {
            perf_buffer->poll(POLL_TIMEOUT);
            tracer->flush();

            if (debug) {
                tracer->show_event_per_sec(&t0);
            }
        }
    }

    fprintf(stderr, "Error: failed to get_perf_buffer()\n");
    return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Library
  Module:    RenderM.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file or its
contents may be copied, reproduced or altered in any way without the express
written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include <stdlib.h>
#include <iostream.h>
#include <string.h>
#include "RenderM.hh"

#ifdef USE_KGLR
#include "KglrRenW.hh"
#endif

vlRenderMaster::vlRenderMaster()
{
}

vlRenderWindow *vlRenderMaster::MakeRenderWindow(char *type)
{

#ifdef USE_KGLR
  if (!strncmp("kglr",type,4))
    {
    vlKglrRenderWindow *ren;
    ren = new vlKglrRenderWindow;
    return (vlRenderWindow *)ren;
    }
#endif

  vlErrorMacro(<<"RenderMaster Error: unable to return render window.\n");
  return (vlRenderWindow *)NULL;
}

vlRenderWindow *vlRenderMaster::MakeRenderWindow(void)
{
  return (this->MakeRenderWindow(getenv("VL_RENDERER")));
}
<commit_msg>added starbase<commit_after>/*=========================================================================

  Program:   Visualization Library
  Module:    RenderM.cc
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

This file is part of the Visualization Library. No part of this file or its
contents may be copied, reproduced or altered in any way without the express
written consent of the authors.

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen 1993, 1994

=========================================================================*/
#include <stdlib.h>
#include <iostream.h>
#include <string.h>
#include "RenderM.hh"

#ifdef USE_KGLR
#include "KglrRenW.hh"
#endif

#ifdef USE_SBR
#include "SbrRenW.hh"
#endif

vlRenderMaster::vlRenderMaster()
{
}

vlRenderWindow *vlRenderMaster::MakeRenderWindow(char *type)
{

#ifdef USE_KGLR
  if (!strncmp("kglr",type,4))
    {
    vlKglrRenderWindow *ren;
    ren = new vlKglrRenderWindow;
    return (vlRenderWindow *)ren;
    }
#endif

#ifdef USE_SBR
  if (!strncmp("sbr",type,4))
    {
    vlSbrRenderWindow *ren;
    ren = new vlSbrRenderWindow;
    return (vlRenderWindow *)ren;
    }
#endif

  vlErrorMacro(<<"RenderMaster Error: unable to return render window.\n");
  return (vlRenderWindow *)NULL;
}

vlRenderWindow *vlRenderMaster::MakeRenderWindow(void)
{
  char *temp;

  // if nothing is set then try kglr
  temp = getenv("VL_RENDERER");
  if (!temp) temp = "kglr";

  return (this->MakeRenderWindow(temp));
}
<|endoftext|>


<commit_before>/*
 * Mickey Scheme
 *
 * Copyright (C) 2011-2012 Christian Stigen Larsen <csl@sublevel3.org>
 * http://csl.sublevel3.org                              _
 *                                                        \
 * Distributed under the LGPL 2.1; see LICENSE            /\
 * Please post bugfixes and suggestions to the author.   /  \_
 *
 */

#include <stdarg.h>
#include "types/real_t.h"
#include "print.h"
#include "util.h"
#include "primitives.h"

std::string sprint(const cons_t* p, std::string& s, bool escape)
{
  switch ( type_of(p) ) {
  case NIL:          return s;
  case BOOLEAN:      return s + to_s(p->boolean);
  case CHAR:         return s + to_s(p->character, escape);
  case REAL:         return s + to_s(p->number.real);
  case INTEGER:      return s + to_s(p->number.integer);
  case RATIONAL:     return s + to_s(p->number.rational);
  case CLOSURE:      return s + (escape? to_s(p->closure) : "");
  case SYMBOL:       return s + *p->symbol;
  case STRING:       return s + (escape? "\"" + encode_str(p->string) + "\"" : p->string);
  case VECTOR:       return s + sprint(p->vector, s, escape);
  case BYTEVECTOR:   return s + sprint(p->bytevector, s, escape);
  case CONTINUATION: return s + (escape? to_s(p->continuation) : "");
  case SYNTAX:       return s + sprint(p->syntax->transformer, s, escape);
  case PORT:         return s + sprint(p->port, s, escape);
  case ENVIRONMENT:  return s + sprint(p->environment, s, escape);
  case POINTER:      return s + sprint(p->pointer, s, escape);
  case PAIR: {
    std::string head = sprint(car(p), s, escape);
    std::string tail = sprint(cdr(p), s, escape);

    bool paren = type_of(car(p))==PAIR;
    bool dotted = atomp(cdr(p)) && !nullp(cdr(p)) && !emptylistp(cadr(p));

    return s
      + (paren? "(" : "")
      + head
      + (paren? ")" : "")
      + (!tail.empty() ? " " : "")
      + (dotted? ". " : "")
      + tail;
  }}

  return s;
}

std::string sprint(const cons_t* p)
{
  std::string s;
  return sprint(listp(p) ? cons(p) : p, s, true);
}

std::string print(const cons_t* p)
{
  // the ?-operator below is a dirty trick to be
  // able to print lists with parenthesis
  std::string s;
  return sprint(listp(p) ? cons(p) : p, s, false);
}

std::string sprint(const vector_t* v, std::string& r, bool)
{
  const std::vector<cons_t*>& p = v->vector;
  std::string s;
  s += "#(";

  for ( std::vector<cons_t*>::const_iterator i = p.begin();
        i != p.end(); ++i )
  {
    if ( i != p.begin() ) s += " ";
    if ( listp(*i) ) s += "(";

    if ( nullp(*i) )
      s += to_s(*i);
    else
      s += sprint(*i, r, true);

    if ( listp(*i) ) s += ")";
  }

  s += ")";
  return s;
}

std::string sprint(const bytevector_t* v, std::string&, bool)
{
  const std::vector<uint8_t>& p = v->bytevector;
  std::string s;
  s += "#u8(";

  std::string space = "";

  for ( std::vector<uint8_t>::const_iterator i = p.begin();
        i != p.end(); ++i )
  {
    s += space + to_s(*i);
    space = " ";
  }

  s += ")";
  return s;
}

std::string sprint(const port_t* p, std::string&, bool)
{
  return format("#<port %p %s%s%s%s>", p, p->readable? "R" : "", p->writable? "W" : "",
      p->istextual()? "T" : "", p->isbinary()? "B" : "");
}

std::string sprint(const environment_t* p, std::string&, bool)
{
  return format("#<environment %p>", p);
}

std::string sprint(const pointer_t* p, std::string&, bool)
{
  return format("#<pointer '%s' %p>", p->tag, p->value);
}

std::string to_s(integer_t n)
{
  char buf[64];
  sprintf(buf, "%d", n);
  return std::string(buf);
}

std::string to_s(rational_t n)
{
  char buf[64];
  sprintf(buf, "%d/%d", n.numerator, n.denominator);
  return std::string(buf);
}

std::string to_s(real_t n)
{
  if ( is_nan(n) ) return "+nan.0";
  if ( is_neg_inf(n) ) return "-inf.0";
  if ( is_pos_inf(n) ) return "+inf.0";

  char buf[64];
  sprintf(buf, "%g", n);
  return std::string(buf);
}

std::string to_s(bool f)
{
  return std::string(f? "#t" : "#f");
}

std::string format(const char* fmt, ...)
{
  char buf[1024] = {'\0'};
  va_list list;
  va_start(list, fmt);
  vsprintf(buf, fmt, list);
  va_end(list);
  return std::string(buf);
}

std::string to_s(enum type_t type)
{
  switch ( type ) {
  case NIL:          return "nil";          break;
  case BOOLEAN:      return "boolean";      break;
  case CHAR:         return "char";         break;
  case REAL:         return "real";         break;
  case INTEGER:      return "integer";      break;
  case RATIONAL:     return "rational";     break;
  case CLOSURE:      return "closure";      break;
  case PAIR:         return "pair";         break;
  case SYMBOL:       return "symbol";       break;
  case SYNTAX:       return "syntax";       break;
  case STRING:       return "string";       break;
  case VECTOR:       return "vector";       break;
  case CONTINUATION: return "continuation"; break;
  case BYTEVECTOR:   return "bytevector";   break;
  case PORT:         return "port";         break;
  case ENVIRONMENT:  return "environment";  break;
  case POINTER:      return "pointer";      break;
  }

  return "#<unknown type>";
}

std::string to_s(cons_t *p)
{
  switch ( type_of(p) ) {
  case NIL:      return "#<nil>";
  case BOOLEAN:  return to_s(p->boolean);
  case CHAR:     return to_s(p->character, false);
  case REAL:     return to_s(p->number.real);
  case INTEGER:  return to_s(p->number.integer);
  case RATIONAL: return to_s(p->number.rational);
  case CLOSURE:  return format("#<closure %p>", p->closure);
  case PAIR:     return to_s(car(p)) + " . " + to_s(cdr(p));
  case SYMBOL:   return *p->symbol;
  case SYNTAX:   return format("#<syntax_transformer %p>", p->syntax);
  case STRING:   return p->string;
  case VECTOR:   return format("#<vector %p>", p->vector);
  case PORT:     return format("#<port %p>", p->port);
  case CONTINUATION: return format("#<continuation %p>", p->continuation);
  case BYTEVECTOR:   return format("#<bytevector %p>", p->bytevector);
  case ENVIRONMENT:  return format("#<environment %p>", p->environment);
  case POINTER:      return format("#<pointer '%s' %p>",
                              p->pointer->tag, p->pointer->value);
  }

  return "#<unknown type>";
}

std::string to_s(closure_t* p)
{
  return format("#<closure %p>", p);
}

std::string to_s(continuation_t* p)
{
  return format("#<continuation %p>", p);
}

std::string to_s(vector_t* p)
{
  return format("#<vector %p>", p);
}

std::string to_s(port_t* p)
{
  return format("#<port %p>", p);
}

std::string to_s(char p, bool escape)
{
  return escape?
    format("#\\x%x;", static_cast<int>(p)) :
    format("%c", p);
}

std::string to_s(environment_t* e)
{
  return format("#<environment %p", e);
}

<commit_msg>Character literals do not end with semicolon<commit_after>/*
 * Mickey Scheme
 *
 * Copyright (C) 2011-2012 Christian Stigen Larsen <csl@sublevel3.org>
 * http://csl.sublevel3.org                              _
 *                                                        \
 * Distributed under the LGPL 2.1; see LICENSE            /\
 * Please post bugfixes and suggestions to the author.   /  \_
 *
 */

#include <stdarg.h>
#include "types/real_t.h"
#include "print.h"
#include "util.h"
#include "primitives.h"

std::string sprint(const cons_t* p, std::string& s, bool escape)
{
  switch ( type_of(p) ) {
  case NIL:          return s;
  case BOOLEAN:      return s + to_s(p->boolean);
  case CHAR:         return s + to_s(p->character, escape);
  case REAL:         return s + to_s(p->number.real);
  case INTEGER:      return s + to_s(p->number.integer);
  case RATIONAL:     return s + to_s(p->number.rational);
  case CLOSURE:      return s + (escape? to_s(p->closure) : "");
  case SYMBOL:       return s + *p->symbol;
  case STRING:       return s + (escape? "\"" + encode_str(p->string) + "\"" : p->string);
  case VECTOR:       return s + sprint(p->vector, s, escape);
  case BYTEVECTOR:   return s + sprint(p->bytevector, s, escape);
  case CONTINUATION: return s + (escape? to_s(p->continuation) : "");
  case SYNTAX:       return s + sprint(p->syntax->transformer, s, escape);
  case PORT:         return s + sprint(p->port, s, escape);
  case ENVIRONMENT:  return s + sprint(p->environment, s, escape);
  case POINTER:      return s + sprint(p->pointer, s, escape);
  case PAIR: {
    std::string head = sprint(car(p), s, escape);
    std::string tail = sprint(cdr(p), s, escape);

    bool paren = type_of(car(p))==PAIR;
    bool dotted = atomp(cdr(p)) && !nullp(cdr(p)) && !emptylistp(cadr(p));

    return s
      + (paren? "(" : "")
      + head
      + (paren? ")" : "")
      + (!tail.empty() ? " " : "")
      + (dotted? ". " : "")
      + tail;
  }}

  return s;
}

std::string sprint(const cons_t* p)
{
  std::string s;
  return sprint(listp(p) ? cons(p) : p, s, true);
}

std::string print(const cons_t* p)
{
  // the ?-operator below is a dirty trick to be
  // able to print lists with parenthesis
  std::string s;
  return sprint(listp(p) ? cons(p) : p, s, false);
}

std::string sprint(const vector_t* v, std::string& r, bool)
{
  const std::vector<cons_t*>& p = v->vector;
  std::string s;
  s += "#(";

  for ( std::vector<cons_t*>::const_iterator i = p.begin();
        i != p.end(); ++i )
  {
    if ( i != p.begin() ) s += " ";
    if ( listp(*i) ) s += "(";

    if ( nullp(*i) )
      s += to_s(*i);
    else
      s += sprint(*i, r, true);

    if ( listp(*i) ) s += ")";
  }

  s += ")";
  return s;
}

std::string sprint(const bytevector_t* v, std::string&, bool)
{
  const std::vector<uint8_t>& p = v->bytevector;
  std::string s;
  s += "#u8(";

  std::string space = "";

  for ( std::vector<uint8_t>::const_iterator i = p.begin();
        i != p.end(); ++i )
  {
    s += space + to_s(*i);
    space = " ";
  }

  s += ")";
  return s;
}

std::string sprint(const port_t* p, std::string&, bool)
{
  return format("#<port %p %s%s%s%s>", p, p->readable? "R" : "", p->writable? "W" : "",
      p->istextual()? "T" : "", p->isbinary()? "B" : "");
}

std::string sprint(const environment_t* p, std::string&, bool)
{
  return format("#<environment %p>", p);
}

std::string sprint(const pointer_t* p, std::string&, bool)
{
  return format("#<pointer '%s' %p>", p->tag, p->value);
}

std::string to_s(integer_t n)
{
  char buf[64];
  sprintf(buf, "%d", n);
  return std::string(buf);
}

std::string to_s(rational_t n)
{
  char buf[64];
  sprintf(buf, "%d/%d", n.numerator, n.denominator);
  return std::string(buf);
}

std::string to_s(real_t n)
{
  if ( is_nan(n) ) return "+nan.0";
  if ( is_neg_inf(n) ) return "-inf.0";
  if ( is_pos_inf(n) ) return "+inf.0";

  char buf[64];
  sprintf(buf, "%g", n);
  return std::string(buf);
}

std::string to_s(bool f)
{
  return std::string(f? "#t" : "#f");
}

std::string format(const char* fmt, ...)
{
  char buf[1024] = {'\0'};
  va_list list;
  va_start(list, fmt);
  vsprintf(buf, fmt, list);
  va_end(list);
  return std::string(buf);
}

std::string to_s(enum type_t type)
{
  switch ( type ) {
  case NIL:          return "nil";          break;
  case BOOLEAN:      return "boolean";      break;
  case CHAR:         return "char";         break;
  case REAL:         return "real";         break;
  case INTEGER:      return "integer";      break;
  case RATIONAL:     return "rational";     break;
  case CLOSURE:      return "closure";      break;
  case PAIR:         return "pair";         break;
  case SYMBOL:       return "symbol";       break;
  case SYNTAX:       return "syntax";       break;
  case STRING:       return "string";       break;
  case VECTOR:       return "vector";       break;
  case CONTINUATION: return "continuation"; break;
  case BYTEVECTOR:   return "bytevector";   break;
  case PORT:         return "port";         break;
  case ENVIRONMENT:  return "environment";  break;
  case POINTER:      return "pointer";      break;
  }

  return "#<unknown type>";
}

std::string to_s(cons_t *p)
{
  switch ( type_of(p) ) {
  case NIL:      return "#<nil>";
  case BOOLEAN:  return to_s(p->boolean);
  case CHAR:     return to_s(p->character, false);
  case REAL:     return to_s(p->number.real);
  case INTEGER:  return to_s(p->number.integer);
  case RATIONAL: return to_s(p->number.rational);
  case CLOSURE:  return format("#<closure %p>", p->closure);
  case PAIR:     return to_s(car(p)) + " . " + to_s(cdr(p));
  case SYMBOL:   return *p->symbol;
  case SYNTAX:   return format("#<syntax_transformer %p>", p->syntax);
  case STRING:   return p->string;
  case VECTOR:   return format("#<vector %p>", p->vector);
  case PORT:     return format("#<port %p>", p->port);
  case CONTINUATION: return format("#<continuation %p>", p->continuation);
  case BYTEVECTOR:   return format("#<bytevector %p>", p->bytevector);
  case ENVIRONMENT:  return format("#<environment %p>", p->environment);
  case POINTER:      return format("#<pointer '%s' %p>",
                              p->pointer->tag, p->pointer->value);
  }

  return "#<unknown type>";
}

std::string to_s(closure_t* p)
{
  return format("#<closure %p>", p);
}

std::string to_s(continuation_t* p)
{
  return format("#<continuation %p>", p);
}

std::string to_s(vector_t* p)
{
  return format("#<vector %p>", p);
}

std::string to_s(port_t* p)
{
  return format("#<port %p>", p);
}

std::string to_s(char p, bool escape)
{
  return escape?
    format("#\\x%x", static_cast<int>(p)) :
    format("%c", p);
}

std::string to_s(environment_t* e)
{
  return format("#<environment %p", e);
}

<|endoftext|>


<commit_before>/**
 * Flann LSH
 */

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include <flann/flann.hpp>

using namespace flann;
using namespace std;

void load_from_file(Matrix<float>& dataset, const string& filename) {
  ifstream dfile(filename);
  if (!dfile.is_open()) {
    cout << "unable to open data set file: " << filename << endl;
    exit(1);
  }

  string line;

  int i = 0;
  while (dfile >> line) {
    for (unsigned j = 0; i < line.length(); i++) {
      dataset[i][j] = line[j]-'0';
    }
    i++;
  }

  dfile.close();
}

int main(int argc, char** argv) {
    Matrix<float> dataset;
    Matrix<float> query;
    load_from_file(dataset, "data/files/d10nd16");
    load_from_file(query, "data/files/d10nq4");

    int d = 10;
    Matrix<int> indices(new int[query.rows*d], query.rows, d);
    Matrix<float> dists(new float[query.rows*d], query.rows, d);

    // construct a hierarchical clustering index
    // default paramaters:
    // branching factor: 32
    // centers: random
    // number of parallel trees: 4
    // leaf_max_size: 100
    Index<L2<float>> index(dataset, flann::HierarchicalClusteringIndexParams());
    index.buildIndex();

    // do a radius search, using 128 checks
    // checks : specifies the maximum leafs to visit when searching for neigbors
    int n = index.radiusSearch(query, indices, dists, 3, flann::SearchParams(128));
    cout << "number of nearest neighbors: " << n << endl;

    delete[] dataset.ptr();
    delete[] query.ptr();
    delete[] indices.ptr();
    delete[] dists.ptr();

    return 0;
}
<commit_msg>Bury flann. Works (to some extent)<commit_after>/**
 * Flann LSH
 */

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include <flann/flann.hpp>

using namespace flann;
using namespace std;

void load_from_file(Matrix<float>& dataset, const string& filename) {
  ifstream dfile(filename);
  if (!dfile.is_open()) {
    cout << "unable to open data set file: " << filename << endl;
    exit(1);
  }

  string line;

  int i = 0;
  while (dfile >> line) {
    for (unsigned j = 0; i < line.length(); i++) {
      dataset[i][j] = line[j]-'0';
    }
    i++;
  }

  dfile.close();
}

int main(int argc, char** argv) {
    int d = 10;
    Matrix<float> dataset(new float[16*d], 16, d);
    Matrix<float> query(new float[4*d], 4, d);
    load_from_file(dataset, "data/files/d10nd16");
    load_from_file(query, "data/files/d10nq4");

    Matrix<int> indices(new int[query.rows*d], query.rows, d);
    Matrix<float> dists(new float[query.rows*d], query.rows, d);

    // construct a hierarchical clustering index
    // default paramaters:
    // branching factor: 32
    // centers: random
    // number of parallel trees: 4
    // leaf_max_size: 100
    Index<L2<float>> index(dataset, flann::HierarchicalClusteringIndexParams());
    index.buildIndex();

    // do a radius search, using 128 checks
    // checks : specifies the maximum leafs to visit when searching for neigbors
    int n = index.radiusSearch(query, indices, dists, 3, flann::SearchParams(128));
    cout << "number of nearest neighbors: " << n << endl;

    delete[] dataset.ptr();
    delete[] query.ptr();
    delete[] indices.ptr();
    delete[] dists.ptr();

    return 0;
}
<|endoftext|>


<commit_before>#include "chrono_parallel/constraints/ChConstraintBilateral.h"
#include "lcp/ChLcpConstraintTwoBodies.h"
#include "physics/ChBody.h"
using namespace chrono;

using blaze::DenseSubvector;
using blaze::subvector;

void ChConstraintBilateral::Build_b()
{
  std::vector<ChLcpConstraint*>& mconstraints = data_container->lcp_system_descriptor->GetConstraintsList();

#pragma omp parallel for
  for (int index = 0; index < num_bilaterals; index++) {
    int cntr = data_container->host_data.bilateral_mapping[index];
    ChLcpConstraintTwoBodies* mbilateral = (ChLcpConstraintTwoBodies*)(mconstraints[cntr]);
    data_container->host_data.b[index + num_unilaterals] = mbilateral->Get_b_i();
  }
}

void ChConstraintBilateral::Build_E()
{
#pragma omp parallel for
  for (int index = 0; index < num_bilaterals; index++) {
    data_container->host_data.E[index + num_unilaterals] = 0;
  }
}

void ChConstraintBilateral::Build_D()
{
  data_container->host_data.gamma_bilateral.resize(num_bilaterals);

  // Grab the list of all bilateral constraints present in the system
  // (note that this includes possibly inactive constraints)
  std::vector<ChLcpConstraint*>& mconstraints = data_container->lcp_system_descriptor->GetConstraintsList();

  // Loop over the active constraints and fill in the rows of the Jacobian,
  // taking into account the type of each constraint.
  CompressedMatrix<real>& D_T = data_container->host_data.D_T;
#pragma omp parallel for
  for (int index = 0; index < num_bilaterals; index++) {
    int cntr = data_container->host_data.bilateral_mapping[index];
    int type = data_container->host_data.bilateral_type[cntr];
    int row = index + num_unilaterals;

    ChLcpConstraintTwoBodies* mbilateral = (ChLcpConstraintTwoBodies*)(mconstraints[cntr]);
    mconstraints[cntr]->Update_auxiliary();

    int idA = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_a()))->GetUserData())->GetId();
    int idB = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_b()))->GetUserData())->GetId();
    int colA = idA * 6;
    int colB = idB * 6;

    D_T(row, colA + 0) = mbilateral->Get_Cq_a()->GetElementN(0);
    D_T(row, colA + 1) = mbilateral->Get_Cq_a()->GetElementN(1);
    D_T(row, colA + 2) = mbilateral->Get_Cq_a()->GetElementN(2);

    D_T(row, colA + 3) = mbilateral->Get_Cq_a()->GetElementN(3);
    D_T(row, colA + 4) = mbilateral->Get_Cq_a()->GetElementN(4);
    D_T(row, colA + 5) = mbilateral->Get_Cq_a()->GetElementN(5);

    D_T(row, colB + 0) = mbilateral->Get_Cq_b()->GetElementN(0);
    D_T(row, colB + 1) = mbilateral->Get_Cq_b()->GetElementN(1);
    D_T(row, colB + 2) = mbilateral->Get_Cq_b()->GetElementN(2);

    D_T(row, colB + 3) = mbilateral->Get_Cq_b()->GetElementN(3);
    D_T(row, colB + 4) = mbilateral->Get_Cq_b()->GetElementN(4);
    D_T(row, colB + 5) = mbilateral->Get_Cq_b()->GetElementN(5);
  }
}

void ChConstraintBilateral::GenerateSparsity()
{
  // Grab the list of all bilateral constraints present in the system
  // (note that this includes possibly inactive constraints)
  std::vector<ChLcpConstraint*>& mconstraints = data_container->lcp_system_descriptor->GetConstraintsList();

  // Loop over the active constraints and fill in the sparsity pattern of the
  // Jacobian, taking into account the type of each constraint.
  // Note that the data for a Blaze compressed matrix must be filled in increasing
  // order of the column index for each row.
  CompressedMatrix<real>& D_T = data_container->host_data.D_T;

  for (int index = 0; index < num_bilaterals; index++) {
    int cntr = data_container->host_data.bilateral_mapping[index];
    int type = data_container->host_data.bilateral_type[cntr];
    int row = index + num_unilaterals;

    ChLcpConstraintTwoBodies* mbilateral = (ChLcpConstraintTwoBodies*)(mconstraints[cntr]);

    int idA = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_a()))->GetUserData())->GetId();
    int idB = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_b()))->GetUserData())->GetId();
    int col1 = idA * 6;
    int col2 = idB * 6;
    if (idA > idB) {
      col1 = idB * 6;
      col2 = idA * 6;
    }

    D_T.append(row, col1 + 0, 1); D_T.append(row, col1 + 1, 1); D_T.append(row, col1 + 2, 1);
    D_T.append(row, col1 + 3, 1); D_T.append(row, col1 + 4, 1); D_T.append(row, col1 + 5, 1);

    D_T.append(row, col2 + 0, 1); D_T.append(row, col2 + 1, 1); D_T.append(row, col2 + 2, 1);
    D_T.append(row, col2 + 3, 1); D_T.append(row, col2 + 4, 1); D_T.append(row, col2 + 5, 1);

    D_T.finalize(row);
  }
}

<commit_msg>Fill-in constraint Jacobian for shaft-shaft bilateral constraints.<commit_after>#include "chrono_parallel/constraints/ChConstraintBilateral.h"
#include "lcp/ChLcpConstraintTwoBodies.h"
#include "lcp/ChLcpConstraintTwoGeneric.h"
#include "lcp/ChLcpConstraintThreeGeneric.h"
#include "physics/ChBody.h"
#include "physics/ChShaft.h"

using namespace chrono;

using blaze::DenseSubvector;
using blaze::subvector;

void ChConstraintBilateral::Build_b()
{
  std::vector<ChLcpConstraint*>& mconstraints = data_container->lcp_system_descriptor->GetConstraintsList();

#pragma omp parallel for
  for (int index = 0; index < num_bilaterals; index++) {
    int cntr = data_container->host_data.bilateral_mapping[index];
    ChLcpConstraintTwoBodies* mbilateral = (ChLcpConstraintTwoBodies*)(mconstraints[cntr]);
    data_container->host_data.b[index + num_unilaterals] = mbilateral->Get_b_i();
  }
}

void ChConstraintBilateral::Build_E()
{
#pragma omp parallel for
  for (int index = 0; index < num_bilaterals; index++) {
    data_container->host_data.E[index + num_unilaterals] = 0;
  }
}

void ChConstraintBilateral::Build_D()
{
  data_container->host_data.gamma_bilateral.resize(num_bilaterals);

  // Grab the list of all bilateral constraints present in the system
  // (note that this includes possibly inactive constraints)
  std::vector<ChLcpConstraint*>& mconstraints = data_container->lcp_system_descriptor->GetConstraintsList();

  // Loop over the active constraints and fill in the rows of the Jacobian,
  // taking into account the type of each constraint.
  CompressedMatrix<real>& D_T = data_container->host_data.D_T;

//#pragma omp parallel for
  for (int index = 0; index < num_bilaterals; index++) {
    int cntr = data_container->host_data.bilateral_mapping[index];
    int type = data_container->host_data.bilateral_type[cntr];
    int row = index + num_unilaterals;

    mconstraints[cntr]->Update_auxiliary();

    switch (type) {

    case BODY_BODY:
    {
      ChLcpConstraintTwoBodies* mbilateral = (ChLcpConstraintTwoBodies*)(mconstraints[cntr]);

      int idA = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_a()))->GetUserData())->GetId();
      int idB = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_b()))->GetUserData())->GetId();
      int colA = idA * 6;
      int colB = idB * 6;

      D_T(row, colA + 0) = mbilateral->Get_Cq_a()->GetElementN(0);
      D_T(row, colA + 1) = mbilateral->Get_Cq_a()->GetElementN(1);
      D_T(row, colA + 2) = mbilateral->Get_Cq_a()->GetElementN(2);

      D_T(row, colA + 3) = mbilateral->Get_Cq_a()->GetElementN(3);
      D_T(row, colA + 4) = mbilateral->Get_Cq_a()->GetElementN(4);
      D_T(row, colA + 5) = mbilateral->Get_Cq_a()->GetElementN(5);

      D_T(row, colB + 0) = mbilateral->Get_Cq_b()->GetElementN(0);
      D_T(row, colB + 1) = mbilateral->Get_Cq_b()->GetElementN(1);
      D_T(row, colB + 2) = mbilateral->Get_Cq_b()->GetElementN(2);

      D_T(row, colB + 3) = mbilateral->Get_Cq_b()->GetElementN(3);
      D_T(row, colB + 4) = mbilateral->Get_Cq_b()->GetElementN(4);
      D_T(row, colB + 5) = mbilateral->Get_Cq_b()->GetElementN(5);
    }
      break;

    case SHAFT_SHAFT:
    {
      ChLcpConstraintTwoGeneric* mbilateral = (ChLcpConstraintTwoGeneric*)(mconstraints[cntr]);

      int idA = ((ChLcpVariablesShaft*)(mbilateral->GetVariables_a()))->GetShaft()->GetId();
      int idB = ((ChLcpVariablesShaft*)(mbilateral->GetVariables_b()))->GetShaft()->GetId();
      int colA = data_container->num_bodies * 6 + idA;
      int colB = data_container->num_bodies * 6 + idB;

      D_T(row, colA) = mbilateral->Get_Cq_a()->GetElementN(0);
      D_T(row, colB) = mbilateral->Get_Cq_b()->GetElementN(0);
    }
      break;

    }
  }
}

void ChConstraintBilateral::GenerateSparsity()
{
  // Grab the list of all bilateral constraints present in the system
  // (note that this includes possibly inactive constraints)
  std::vector<ChLcpConstraint*>& mconstraints = data_container->lcp_system_descriptor->GetConstraintsList();

  // Loop over the active constraints and fill in the sparsity pattern of the
  // Jacobian, taking into account the type of each constraint.
  // Note that the data for a Blaze compressed matrix must be filled in increasing
  // order of the column index for each row.
  CompressedMatrix<real>& D_T = data_container->host_data.D_T;

  for (int index = 0; index < num_bilaterals; index++) {
    int cntr = data_container->host_data.bilateral_mapping[index];
    int type = data_container->host_data.bilateral_type[cntr];
    int row = index + num_unilaterals;
    int col1;
    int col2;

    switch (type) {

    case BODY_BODY:
    {
      ChLcpConstraintTwoBodies* mbilateral = (ChLcpConstraintTwoBodies*)(mconstraints[cntr]);

      int idA = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_a()))->GetUserData())->GetId();
      int idB = ((ChBody*)((ChLcpVariablesBody*)(mbilateral->GetVariables_b()))->GetUserData())->GetId();
      if (idA < idB) {
        col1 = idA * 6;
        col2 = idB * 6;
      } else {
        col1 = idB * 6;
        col2 = idA * 6;
      }

      D_T.append(row, col1 + 0, 1); D_T.append(row, col1 + 1, 1); D_T.append(row, col1 + 2, 1);
      D_T.append(row, col1 + 3, 1); D_T.append(row, col1 + 4, 1); D_T.append(row, col1 + 5, 1);

      D_T.append(row, col2 + 0, 1); D_T.append(row, col2 + 1, 1); D_T.append(row, col2 + 2, 1);
      D_T.append(row, col2 + 3, 1); D_T.append(row, col2 + 4, 1); D_T.append(row, col2 + 5, 1);
    }
      break;

    case SHAFT_SHAFT:
    {
      ChLcpConstraintTwoGeneric* mbilateral = (ChLcpConstraintTwoGeneric*)(mconstraints[cntr]);

      int idA = ((ChLcpVariablesShaft*)(mbilateral->GetVariables_a()))->GetShaft()->GetId();
      int idB = ((ChLcpVariablesShaft*)(mbilateral->GetVariables_b()))->GetShaft()->GetId();
      if (idA < idB) {
        col1 = data_container->num_bodies * 6 + idA;
        col2 = data_container->num_bodies * 6 + idB;
      } else {
        col1 = data_container->num_bodies * 6 + idB;
        col2 = data_container->num_bodies * 6 + idA;
      }

      D_T.append(row, col1, 1);
      D_T.append(row, col2, 1);
    }
      break;

    }

    D_T.finalize(row);
  }
}

<|endoftext|>


<commit_before>/**
 * \file
 * \brief SortedContainerBase and SortedContainer classes header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-09-07
 */

#ifndef INCLUDE_DISTORTOS_CONTAINERS_SORTEDCONTAINER_HPP_
#define INCLUDE_DISTORTOS_CONTAINERS_SORTEDCONTAINER_HPP_

#include <algorithm>

namespace distortos
{

namespace containers
{

/**
 * \brief Base for SortedContainer - can be used to get common iterator.
 *
 * \param Container is the underlying container, it must provide following functions: begin(), emplace(), end(), size()
 * and splice(). It must contain following types: iterator and value_type.
 */

template<typename Container>
class SortedContainerBase : public Container
{
public:

	/// base of SortedContainerBase
	using Base = Container;
};

/**
 * \brief SortedContainer class is a container that keeps the elements sorted during emplace of transfer.
 *
 * \note The elements are sorted as long as the user does not modify the contents via iterators.
 *
 * \param Container is the underlying container, it must provide following functions: begin(), emplace(), end(), size()
 * and splice(). It must contain following types: iterator and value_type.
 * \param Compare is a type of functor used for comparison, std::less results in descending order, std::greater - in
 * ascending order.
 */

template<typename Container, typename Compare>
class SortedContainer : private SortedContainerBase<Container>
{
public:

	/**
	 * \brief SortedContainer's constructor
	 *
	 * \param [in] compare is a reference to Compare object used to copy-construct comparison functor
	 */

	explicit SortedContainer(const Compare& compare = Compare{}) :
            compare_(compare)
	{}

	/// base of SortedContainer
	using Base = SortedContainerBase<Container>;

	using typename Base::iterator;
	using typename Base::value_type;

	using Base::begin;
	using Base::empty;
	using Base::erase;
	using Base::end;
	using Base::size;

	/**
	 * \brief Sorted emplace()
	 *
	 * \param Args are types of argument for value_type constructor
	 *
	 * \param [in] args are arguments for value_type constructor
	 *
	 * \return iterator to emplaced element
	 */

	template<typename... Args>
	iterator sortedEmplace(Args&&... args)
	{
		Base::emplace(begin(), std::forward<Args>(args)...);
		const auto it = begin();
		sortedSplice(*this, it);
		return it;
	}

	/**
	 * \brief Sorted splice()
	 *
	 * \param [in] other is the container from which the object is transfered
	 * \param [in] other_position is the position of the transfered object in the other container
	 */

	void sortedSplice(SortedContainer& other, const iterator other_position)
	{
		const auto insert_position = findInsertPosition_(*other_position);
		Base::splice(insert_position, other, other_position);
	}

private:

	/**
	 * \brief Finds insert position that satisfies sorting criteria.
	 *
	 * Finds the insert position where Compare of current element and provided value returns true.
	 *
	 * \param [in] value is the value that is going to be emplaced/transfered
	 */

	iterator findInsertPosition_(const value_type& value)
	{
		return std::find_if(begin(), end(),
				[this, &value](const value_type& element) -> bool
				{
					return compare_(element, value);
				}
		);
	}

	/// instance of functor used for comparison
	Compare compare_;
};

}	// namespace containers

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_CONTAINERS_SORTEDCONTAINER_HPP_
<commit_msg>SortedContainer: add option to provide allocator for base container<commit_after>/**
 * \file
 * \brief SortedContainerBase and SortedContainer classes header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-09-07
 */

#ifndef INCLUDE_DISTORTOS_CONTAINERS_SORTEDCONTAINER_HPP_
#define INCLUDE_DISTORTOS_CONTAINERS_SORTEDCONTAINER_HPP_

#include <algorithm>

namespace distortos
{

namespace containers
{

/**
 * \brief Base for SortedContainer - can be used to get common iterator.
 *
 * \param Container is the underlying container, it must provide following functions: begin(), emplace(), end(), size()
 * and splice(). It must contain following types: iterator and value_type.
 */

template<typename Container>
class SortedContainerBase : public Container
{
public:

	/// base of SortedContainerBase
	using Base = Container;

	using Base::Base;
};

/**
 * \brief SortedContainer class is a container that keeps the elements sorted during emplace of transfer.
 *
 * \note The elements are sorted as long as the user does not modify the contents via iterators.
 *
 * \param Container is the underlying container, it must provide following functions: begin(), emplace(), end(), size()
 * and splice(). It must contain following types: allocator_type, iterator and value_type.
 * \param Compare is a type of functor used for comparison, std::less results in descending order, std::greater - in
 * ascending order.
 */

template<typename Container, typename Compare>
class SortedContainer : private SortedContainerBase<Container>
{
public:

	/// base of SortedContainer
	using Base = SortedContainerBase<Container>;

	using typename Base::iterator;
	using typename Base::value_type;
	using typename Base::allocator_type;

	/**
	 * \brief SortedContainer's constructor
	 *
	 * \param [in] compare is a reference to Compare object used to copy-construct comparison functor
	 * \param [in] allocator is a reference to allocator_type object used to copy-construct allocator of base container
	 */

	explicit SortedContainer(const Compare& compare = Compare{}, const allocator_type& allocator = allocator_type{}) :
			Base{allocator},
            compare_(compare)
	{

	}

	using Base::begin;
	using Base::empty;
	using Base::erase;
	using Base::end;
	using Base::size;

	/**
	 * \brief Sorted emplace()
	 *
	 * \param Args are types of argument for value_type constructor
	 *
	 * \param [in] args are arguments for value_type constructor
	 *
	 * \return iterator to emplaced element
	 */

	template<typename... Args>
	iterator sortedEmplace(Args&&... args)
	{
		Base::emplace(begin(), std::forward<Args>(args)...);
		const auto it = begin();
		sortedSplice(*this, it);
		return it;
	}

	/**
	 * \brief Sorted splice()
	 *
	 * \param [in] other is the container from which the object is transfered
	 * \param [in] other_position is the position of the transfered object in the other container
	 */

	void sortedSplice(SortedContainer& other, const iterator other_position)
	{
		const auto insert_position = findInsertPosition_(*other_position);
		Base::splice(insert_position, other, other_position);
	}

private:

	/**
	 * \brief Finds insert position that satisfies sorting criteria.
	 *
	 * Finds the insert position where Compare of current element and provided value returns true.
	 *
	 * \param [in] value is the value that is going to be emplaced/transfered
	 */

	iterator findInsertPosition_(const value_type& value)
	{
		return std::find_if(begin(), end(),
				[this, &value](const value_type& element) -> bool
				{
					return compare_(element, value);
				}
		);
	}

	/// instance of functor used for comparison
	Compare compare_;
};

}	// namespace containers

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_CONTAINERS_SORTEDCONTAINER_HPP_
<|endoftext|>


<commit_before>// Copyright (c) 2009 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=4 sts=4 et fdm=marker cms=\ //\ %s

#include <fstream>

#include "iniphile.hpp"
#include "iniphile/input.hpp"
#include "iniphile/ast.hpp"

iniphile_bridge::iniphile_bridge(std::string const path)
: src(path)
, open_(false)
{
    std::ifstream input(path.c_str(), std::ios_base::binary);
    input.unsetf(std::ios::skipws);
    std::istreambuf_iterator<char> b(input), e;

    iniphile::parse_result cfg(
        iniphile::parse(b, e, std::cerr)
    );

    if (!cfg) {
        return;
    }
    afg = new iniphile::ast::node(iniphile::normalize(*cfg));
    open_ = !!input;
}

iniphile_bridge::~iniphile_bridge()
{
    delete afg;
}

bool
iniphile_bridge::is_open()
{
    return open_;
}

std::string const
iniphile_bridge::path()
{
    return src;
}

std::string const
iniphile_bridge::get_string(std::string const query)
{
    if (!open_) return "";
    return iniphile::get_string(*afg, query);
}
<commit_msg>iniphile::get_string moved to output.hpp<commit_after>// Copyright (c) 2009 Roman Neuhauser
// Distributed under the MIT license (see LICENSE file)
// vim: sw=4 sts=4 et fdm=marker cms=\ //\ %s

#include <fstream>

#include "iniphile.hpp"
#include "iniphile/input.hpp"
#include "iniphile/ast.hpp"
#include "iniphile/output.hpp"

iniphile_bridge::iniphile_bridge(std::string const path)
: src(path)
, open_(false)
{
    std::ifstream input(path.c_str(), std::ios_base::binary);
    input.unsetf(std::ios::skipws);
    std::istreambuf_iterator<char> b(input), e;

    iniphile::parse_result cfg(
        iniphile::parse(b, e, std::cerr)
    );

    if (!cfg) {
        return;
    }
    afg = new iniphile::ast::node(iniphile::normalize(*cfg));
    open_ = !!input;
}

iniphile_bridge::~iniphile_bridge()
{
    delete afg;
}

bool
iniphile_bridge::is_open()
{
    return open_;
}

std::string const
iniphile_bridge::path()
{
    return src;
}

std::string const
iniphile_bridge::get_string(std::string const query)
{
    if (!open_) return "";
    return iniphile::get_string(*afg, query);
}
<|endoftext|>