<commit_before>#ifndef XML11_HPP
#define XML11_HPP

#include <string>
#include <memory>
#include <vector>
#include <iostream>
#include <algorithm>

namespace xml11 {

namespace detail {

using mp_true = std::integral_constant<bool, true>;
using mp_false = std::integral_constant<bool, false>;
template<class... T> struct mp_list {};

template<class T>
struct mp_empty_impl;

template<template<class...> class L>
struct mp_empty_impl<L<>> : mp_true {};

template<template<class...> class L, class T1, class... T>
struct mp_empty_impl<L<T1, T...>> : mp_false {};

template<class ... T> using mp_empty = typename mp_empty_impl<mp_list<T...>>::type;

template<class T, class = typename std::enable_if<decltype(*std::declval<T&>(), true)(true), void>::type>
struct mp_like_pointer_impl {
    static const bool value = true;
};

template<class T, class = typename std::enable_if<decltype(std::to_string(std::declval<T&>()), true)(true), void>::type>
struct mp_can_be_string_impl {
    static const bool value = true;
};

template<class T, class = typename std::enable_if<decltype(std::to_string(*std::declval<T&>()), true)(true), void>::type>
struct mp_can_be_string_from_opt_impl {
    static const bool value = true;
};

} // namespace detail

template<class ... T> using mp_empty = std::is_same<detail::mp_empty<T...>, detail::mp_true>;
template<class T, class U> using mp_same = std::is_same<typename std::decay<T>::type, U>;
template<class T, class U> using mp_same_from_opt = std::is_same<typename std::decay<decltype(*std::declval<T&>())>::type, U>;
template<class T> using mp_integral = std::is_integral<typename std::decay<T>::type>;
template<class T> using mp_like_pointer = detail::mp_like_pointer_impl<T>;
template<class T> using mp_can_be_string = detail::mp_can_be_string_impl<T>;
template<class T> using mp_can_be_string_from_opt = detail::mp_can_be_string_from_opt_impl<T>;

using NodeList = std::vector<class Node>;
using ValueFilter = std::function<std::string (const std::string& value)>;

class Node {
public:
    enum class Type : char {
        ELEMENT = 0,
        ATTRIBUTE = 1,
        OPTIONAL = 2,
    };

    class Xml11Exception final : public std::runtime_error {
    public:
        using std::runtime_error::runtime_error;
    };

public:
    static Node fromString(const std::string& text, const bool isCaseInsensitive=true, ValueFilter valueFilter_ = nullptr);
    std::string toString(const bool indent = true, ValueFilter valueFilter_ = nullptr) const;

public:
    static void AddNode(Node&) noexcept
    {

    }

    static void AddNode_(Node&) noexcept
    {

    }

    template<
        class Head,
        class = typename std::enable_if<
            mp_like_pointer<Head>::value,
            void
        >::type,
        class = void
    >
    static void AddNode_(Node& node, Head&& head)
    {
        if (head) {
            AddNode_(node, *std::forward<Head>(head));
        }
    }

    template<
        class T,
        class = typename std::enable_if<
            mp_same<T, std::string>::value,
            void
        >::type,
        class = void,
        class = void
    >
    static void AddNode_(Node& node, T&& value)
    {
        node.addNode(std::forward<T>(value));
    }

    template<
        class T,
        class = typename std::enable_if<
            !mp_same<T, Node>::value &&
            !mp_same<T, NodeList>::value &&
            !mp_same<T, std::string>::value &&
            !mp_same<T, char*>::value &&
            mp_can_be_string<T>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, T&& value)
    {
        node.text(std::to_string(std::forward<T>(value)));
    }

    template<std::size_t N>
    static void AddNode_(Node& node, const char(&value)[N])
    {
        node.text(value);
    }

    static void AddNode_(Node& node, const Node::Type type)
    {
        node.type(type);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_same<T, Node>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, T&& head)
    {
        node.addNode(std::forward<T>(head));
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_same<T, NodeList>::value,
            void
        >::type,
        class = void
    >
    static void AddNode_(Node& node, T&& head)
    {
        node.addNodes(std::forward<T>(head));
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_like_pointer<T>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, std::initializer_list<T>&& list)
    {
        for (auto&& item : list) {
            AddNode_(node, std::move<T>(item));
        }
    }

    template<
        class T,
        class = typename std::enable_if<
            mp_same<T, Node>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, std::initializer_list<T>&& list)
    {
        AddNode_(node, NodeList(std::move<T>(list)));
    }

    template<
        class T,
        class = typename std::enable_if<
            mp_same<T, NodeList>::value,
            void
        >::type,
        class = void
    >
    static void AddNode_(Node& node, std::initializer_list<T>&& list)
    {
        for (const auto& item : list) {
            AddNode_(node, std::move<T>(item));
        }
    }

    template<class Head, class... Tail>
    static void AddNode_(Node& node, Head&& head, Tail&& ...tail)
    {
        AddNode_(node, std::forward<Head>(head));
        AddNode_(node, std::forward<Tail>(tail)...);
    }

    template<class Head, class... Tail>
    static void AddNode(Node& node, Head&& head, Tail&& ...tail)
    {
        AddNode_(node, std::forward<Head>(head));
        AddNode_(node, std::forward<Tail>(tail)...);
    }

public:
    ~Node() noexcept;
    Node(const std::shared_ptr<class NodeImpl>& node) noexcept;
    Node(const Node& node) noexcept;
    Node(Node&& node) noexcept;
    Node(std::string name);
    Node(std::string name, const Node& node);
    Node(std::string name, Node&& node);
    Node(std::string name, std::string value);
    Node(std::string name, std::string value, const Type type);
    Node(std::string name, const NodeList& nodes);
    Node(std::string name, NodeList&& nodes);

    Node(std::string name, std::initializer_list<Node>&& list)
        : Node(std::move(name), NodeList(std::move(list)))
    {

    }

    template<
        class ... Args,
        class = typename std::enable_if<
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::initializer_list<Node>&& list, Args&& ... args)
        : Node(std::move(name), NodeList(std::move(list)))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_like_pointer<T>::value &&
            mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::initializer_list<T>&& list)
        : Node(std::move(name))
    {
        for (const auto& item : list) {
            AddNode(*const_cast<Node*>(this), std::forward<decltype(item)>(item));
        }
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_like_pointer<T>::value &&
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::initializer_list<T>&& list, Args&& ... args)
        : Node(std::move(name), std::move(list))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class ... Args,
        class = typename std::enable_if<
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::string value, Args&& ... args)
        : Node(std::move(name), std::move(value))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class ... Args,
        class = typename std::enable_if<
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::string value, const Type type, Args&& ... args)
        : Node(std::move(name), std::move(value), type)
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            (mp_same<T, Node>::value || mp_same<T, NodeList>::value) &&
            !mp_empty<Args...>::value,
            void
        >::type,
        class = void
    >
    Node(std::string name, T&& value, Args&& ... args)
        : Node(std::move(name), std::forward<T>(value))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_integral<T>::value &&
            mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, T&& value)
        : Node(std::move(name), std::to_string(std::forward<T>(value)))
    {

    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_integral<T>::value &&
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, T&& value, Args&& ... args)
        : Node(std::move(name), std::to_string(std::forward<T>(value)))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class=typename std::enable_if<
            !mp_same<T, std::string>::value &&
            !mp_same<T, char*>::value &&
            !mp_same_from_opt<T, std::string>::value &&
            mp_can_be_string_from_opt<T>::value,
            T
        >::type,
        class=void
    >
    Node(std::string name, const T& param)
        : Node(std::move(name))
    {
        if (param) {
            this->value(std::to_string(*param));
        }
        else {
            this->pimpl = nullptr;
        }
    }

    template<
        class T,
        class=typename std::enable_if<
            !mp_same<T, std::string>::value &&
            !mp_same<T, char*>::value &&
            mp_same_from_opt<T, std::string>::value,
            T
        >::type,
        class=void,
        class=void
    >
    Node(std::string name, const T& param)
        : Node(std::move(name))
    {
        if (param) {
            this->value(*param);
        }
        else {
            this->pimpl = nullptr;
        }
    }

    Node& operator = (const Node& node) noexcept;
    Node& operator = (Node&& node) noexcept;
    bool operator == (const Node& node) const noexcept;
    bool operator != (const Node& node) const noexcept;
    operator bool() const noexcept;

    NodeList operator [] (const std::string& name);
    NodeList operator [] (const char* name);
    NodeList operator [] (const Type& type);
    const NodeList operator [] (const std::string& name) const;
    const NodeList operator [] (const char* name) const;
    const NodeList operator [] (const Type& type) const;

    NodeList findNodes(const std::string& name);
    NodeList findNodes(const Type& type);
    const NodeList findNodes(const std::string& name) const;
    const NodeList findNodes(const Type& type) const;

    NodeList findNodesXPath(const std::string& name);
    const NodeList findNodesXPath(const std::string& name) const;

    Node operator () (const std::string& name);
    Node operator () (const Type& type);
    const Node operator () (const std::string& name) const;
    const Node operator () (const Type& type) const;

    Node findNode(const std::string& name);
    Node findNode(const Type& type);
    const Node findNode(const std::string& name) const;
    const Node findNode(const Type& type) const;

    Node findNodeXPath(const std::string& name);
    const Node findNodeXPath(const std::string& name) const;

    Node& operator -= (const Node& root);
    Node& operator -= (Node&& root);
    Node& operator -= (const NodeList& nodes);
    Node& operator -= (NodeList&& nodes);

    Node& operator += (const Node& root);
    Node& operator += (Node&& root);
    Node& operator += (const NodeList& nodes);
    Node& operator += (NodeList&& nodes);

    Node& addNode(const Node& node);
    Node& addNode(Node&& node);
    Node& addNode(std::string name);
    Node& addNode(std::string name, std::string value);
    Node& addNode(std::string name, std::string value, const Node::Type type);

    template<
        class T,
        class=typename std::enable_if<
            mp_can_be_string<T>::value,
            T
        >::type
    >
    Node& addNode(std::string name, T&& value)
    {
        return addNode(std::move(name), std::to_string(std::forward<T>(value)));
    }

    Node& addAttribute(std::string name);
    Node& addAttribute(std::string name, std::string value);

    Node& addNodes(const NodeList& node);
    Node& addNodes(NodeList&& node);

    Node& eraseNode(const Node& node);
    Node& eraseNode(Node&& node);
    Node& eraseNodes(const NodeList& node);
    Node& eraseNodes(NodeList&& nodes);

    NodeList nodes();
    const NodeList nodes() const;

    Node::Type type() const;
    void type(const Node::Type type);

    std::string& name() const;
    void name(std::string name);

    std::string& text() const;
    void text(std::string value);

    void value(std::string text);
    void value(const Node& node);
    void value(Node&& node);

    void isCaseInsensitive(const bool isCaseInsensitive);
    bool isCaseInsensitive() const;

    void valueFilter(ValueFilter valueFilter);
    ValueFilter valueFilter() const;

    Node clone(ValueFilter valueFilter_ = nullptr) const;

private:
    std::shared_ptr<class NodeImpl> pimpl {nullptr};
};

namespace literals {

Node operator "" _xml(const char* value, size_t size);

} /* literals */

} /* namespace xml11 */

#endif // XML11_HPP
<commit_msg>Remove iostream and add functional header<commit_after>#ifndef XML11_HPP
#define XML11_HPP

#include <string>
#include <memory>
#include <vector>
#include <functional>

namespace xml11 {

namespace detail {

using mp_true = std::integral_constant<bool, true>;
using mp_false = std::integral_constant<bool, false>;
template<class... T> struct mp_list {};

template<class T>
struct mp_empty_impl;

template<template<class...> class L>
struct mp_empty_impl<L<>> : mp_true {};

template<template<class...> class L, class T1, class... T>
struct mp_empty_impl<L<T1, T...>> : mp_false {};

template<class ... T> using mp_empty = typename mp_empty_impl<mp_list<T...>>::type;

template<class T, class = typename std::enable_if<decltype(*std::declval<T&>(), true)(true), void>::type>
struct mp_like_pointer_impl {
    static const bool value = true;
};

template<class T, class = typename std::enable_if<decltype(std::to_string(std::declval<T&>()), true)(true), void>::type>
struct mp_can_be_string_impl {
    static const bool value = true;
};

template<class T, class = typename std::enable_if<decltype(std::to_string(*std::declval<T&>()), true)(true), void>::type>
struct mp_can_be_string_from_opt_impl {
    static const bool value = true;
};

} // namespace detail

template<class ... T> using mp_empty = std::is_same<detail::mp_empty<T...>, detail::mp_true>;
template<class T, class U> using mp_same = std::is_same<typename std::decay<T>::type, U>;
template<class T, class U> using mp_same_from_opt = std::is_same<typename std::decay<decltype(*std::declval<T&>())>::type, U>;
template<class T> using mp_integral = std::is_integral<typename std::decay<T>::type>;
template<class T> using mp_like_pointer = detail::mp_like_pointer_impl<T>;
template<class T> using mp_can_be_string = detail::mp_can_be_string_impl<T>;
template<class T> using mp_can_be_string_from_opt = detail::mp_can_be_string_from_opt_impl<T>;

using NodeList = std::vector<class Node>;
using ValueFilter = std::function<std::string (const std::string& value)>;

class Node {
public:
    enum class Type : char {
        ELEMENT = 0,
        ATTRIBUTE = 1,
        OPTIONAL = 2,
    };

    class Xml11Exception final : public std::runtime_error {
    public:
        using std::runtime_error::runtime_error;
    };

public:
    static Node fromString(const std::string& text, const bool isCaseInsensitive=true, ValueFilter valueFilter_ = nullptr);
    std::string toString(const bool indent = true, ValueFilter valueFilter_ = nullptr) const;

public:
    static void AddNode(Node&) noexcept
    {

    }

    static void AddNode_(Node&) noexcept
    {

    }

    template<
        class Head,
        class = typename std::enable_if<
            mp_like_pointer<Head>::value,
            void
        >::type,
        class = void
    >
    static void AddNode_(Node& node, Head&& head)
    {
        if (head) {
            AddNode_(node, *std::forward<Head>(head));
        }
    }

    template<
        class T,
        class = typename std::enable_if<
            mp_same<T, std::string>::value,
            void
        >::type,
        class = void,
        class = void
    >
    static void AddNode_(Node& node, T&& value)
    {
        node.addNode(std::forward<T>(value));
    }

    template<
        class T,
        class = typename std::enable_if<
            !mp_same<T, Node>::value &&
            !mp_same<T, NodeList>::value &&
            !mp_same<T, std::string>::value &&
            !mp_same<T, char*>::value &&
            mp_can_be_string<T>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, T&& value)
    {
        node.text(std::to_string(std::forward<T>(value)));
    }

    template<std::size_t N>
    static void AddNode_(Node& node, const char(&value)[N])
    {
        node.text(value);
    }

    static void AddNode_(Node& node, const Node::Type type)
    {
        node.type(type);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_same<T, Node>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, T&& head)
    {
        node.addNode(std::forward<T>(head));
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_same<T, NodeList>::value,
            void
        >::type,
        class = void
    >
    static void AddNode_(Node& node, T&& head)
    {
        node.addNodes(std::forward<T>(head));
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_like_pointer<T>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, std::initializer_list<T>&& list)
    {
        for (auto&& item : list) {
            AddNode_(node, std::move<T>(item));
        }
    }

    template<
        class T,
        class = typename std::enable_if<
            mp_same<T, Node>::value,
            void
        >::type
    >
    static void AddNode_(Node& node, std::initializer_list<T>&& list)
    {
        AddNode_(node, NodeList(std::move<T>(list)));
    }

    template<
        class T,
        class = typename std::enable_if<
            mp_same<T, NodeList>::value,
            void
        >::type,
        class = void
    >
    static void AddNode_(Node& node, std::initializer_list<T>&& list)
    {
        for (const auto& item : list) {
            AddNode_(node, std::move<T>(item));
        }
    }

    template<class Head, class... Tail>
    static void AddNode_(Node& node, Head&& head, Tail&& ...tail)
    {
        AddNode_(node, std::forward<Head>(head));
        AddNode_(node, std::forward<Tail>(tail)...);
    }

    template<class Head, class... Tail>
    static void AddNode(Node& node, Head&& head, Tail&& ...tail)
    {
        AddNode_(node, std::forward<Head>(head));
        AddNode_(node, std::forward<Tail>(tail)...);
    }

public:
    ~Node() noexcept;
    Node(const std::shared_ptr<class NodeImpl>& node) noexcept;
    Node(const Node& node) noexcept;
    Node(Node&& node) noexcept;
    Node(std::string name);
    Node(std::string name, const Node& node);
    Node(std::string name, Node&& node);
    Node(std::string name, std::string value);
    Node(std::string name, std::string value, const Type type);
    Node(std::string name, const NodeList& nodes);
    Node(std::string name, NodeList&& nodes);

    Node(std::string name, std::initializer_list<Node>&& list)
        : Node(std::move(name), NodeList(std::move(list)))
    {

    }

    template<
        class ... Args,
        class = typename std::enable_if<
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::initializer_list<Node>&& list, Args&& ... args)
        : Node(std::move(name), NodeList(std::move(list)))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_like_pointer<T>::value &&
            mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::initializer_list<T>&& list)
        : Node(std::move(name))
    {
        for (const auto& item : list) {
            AddNode(*const_cast<Node*>(this), std::forward<decltype(item)>(item));
        }
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_like_pointer<T>::value &&
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::initializer_list<T>&& list, Args&& ... args)
        : Node(std::move(name), std::move(list))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class ... Args,
        class = typename std::enable_if<
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::string value, Args&& ... args)
        : Node(std::move(name), std::move(value))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class ... Args,
        class = typename std::enable_if<
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, std::string value, const Type type, Args&& ... args)
        : Node(std::move(name), std::move(value), type)
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            (mp_same<T, Node>::value || mp_same<T, NodeList>::value) &&
            !mp_empty<Args...>::value,
            void
        >::type,
        class = void
    >
    Node(std::string name, T&& value, Args&& ... args)
        : Node(std::move(name), std::forward<T>(value))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_integral<T>::value &&
            mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, T&& value)
        : Node(std::move(name), std::to_string(std::forward<T>(value)))
    {

    }

    template<
        class T,
        class ... Args,
        class = typename std::enable_if<
            mp_integral<T>::value &&
            !mp_empty<Args...>::value,
            void
        >::type
    >
    Node(std::string name, T&& value, Args&& ... args)
        : Node(std::move(name), std::to_string(std::forward<T>(value)))
    {
        AddNode(*const_cast<Node*>(this), std::forward<Args>(args)...);
    }

    template<
        class T,
        class=typename std::enable_if<
            !mp_same<T, std::string>::value &&
            !mp_same<T, char*>::value &&
            !mp_same_from_opt<T, std::string>::value &&
            mp_can_be_string_from_opt<T>::value,
            T
        >::type,
        class=void
    >
    Node(std::string name, const T& param)
        : Node(std::move(name))
    {
        if (param) {
            this->value(std::to_string(*param));
        }
        else {
            this->pimpl = nullptr;
        }
    }

    template<
        class T,
        class=typename std::enable_if<
            !mp_same<T, std::string>::value &&
            !mp_same<T, char*>::value &&
            mp_same_from_opt<T, std::string>::value,
            T
        >::type,
        class=void,
        class=void
    >
    Node(std::string name, const T& param)
        : Node(std::move(name))
    {
        if (param) {
            this->value(*param);
        }
        else {
            this->pimpl = nullptr;
        }
    }

    Node& operator = (const Node& node) noexcept;
    Node& operator = (Node&& node) noexcept;
    bool operator == (const Node& node) const noexcept;
    bool operator != (const Node& node) const noexcept;
    operator bool() const noexcept;

    NodeList operator [] (const std::string& name);
    NodeList operator [] (const char* name);
    NodeList operator [] (const Type& type);
    const NodeList operator [] (const std::string& name) const;
    const NodeList operator [] (const char* name) const;
    const NodeList operator [] (const Type& type) const;

    NodeList findNodes(const std::string& name);
    NodeList findNodes(const Type& type);
    const NodeList findNodes(const std::string& name) const;
    const NodeList findNodes(const Type& type) const;

    NodeList findNodesXPath(const std::string& name);
    const NodeList findNodesXPath(const std::string& name) const;

    Node operator () (const std::string& name);
    Node operator () (const Type& type);
    const Node operator () (const std::string& name) const;
    const Node operator () (const Type& type) const;

    Node findNode(const std::string& name);
    Node findNode(const Type& type);
    const Node findNode(const std::string& name) const;
    const Node findNode(const Type& type) const;

    Node findNodeXPath(const std::string& name);
    const Node findNodeXPath(const std::string& name) const;

    Node& operator -= (const Node& root);
    Node& operator -= (Node&& root);
    Node& operator -= (const NodeList& nodes);
    Node& operator -= (NodeList&& nodes);

    Node& operator += (const Node& root);
    Node& operator += (Node&& root);
    Node& operator += (const NodeList& nodes);
    Node& operator += (NodeList&& nodes);

    Node& addNode(const Node& node);
    Node& addNode(Node&& node);
    Node& addNode(std::string name);
    Node& addNode(std::string name, std::string value);
    Node& addNode(std::string name, std::string value, const Node::Type type);

    template<
        class T,
        class=typename std::enable_if<
            mp_can_be_string<T>::value,
            T
        >::type
    >
    Node& addNode(std::string name, T&& value)
    {
        return addNode(std::move(name), std::to_string(std::forward<T>(value)));
    }

    Node& addAttribute(std::string name);
    Node& addAttribute(std::string name, std::string value);

    Node& addNodes(const NodeList& node);
    Node& addNodes(NodeList&& node);

    Node& eraseNode(const Node& node);
    Node& eraseNode(Node&& node);
    Node& eraseNodes(const NodeList& node);
    Node& eraseNodes(NodeList&& nodes);

    NodeList nodes();
    const NodeList nodes() const;

    Node::Type type() const;
    void type(const Node::Type type);

    std::string& name() const;
    void name(std::string name);

    std::string& text() const;
    void text(std::string value);

    void value(std::string text);
    void value(const Node& node);
    void value(Node&& node);

    void isCaseInsensitive(const bool isCaseInsensitive);
    bool isCaseInsensitive() const;

    void valueFilter(ValueFilter valueFilter);
    ValueFilter valueFilter() const;

    Node clone(ValueFilter valueFilter_ = nullptr) const;

private:
    std::shared_ptr<class NodeImpl> pimpl {nullptr};
};

namespace literals {

Node operator "" _xml(const char* value, size_t size);

} /* literals */

} /* namespace xml11 */

#endif // XML11_HPP
<|endoftext|>


<commit_before>#include "CoreAudio.h"
#include "Functiondiscoverykeys_devpkey.h"
#include "../../Logger.h"

// {EC9CB649-7E84-4B42-B367-7FC39BE17806}
static const GUID G3RVXCoreAudioEvent = { 0xec9cb649, 0x7e84, 0x4b42,
    { 0xb3, 0x67, 0x7f, 0xc3, 0x9b, 0xe1, 0x78, 0x6 } };

HRESULT CoreAudio::Init() {
    HRESULT hr;

    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator),
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&_devEnumerator));

    if (SUCCEEDED(hr)) {
        hr = _devEnumerator->RegisterEndpointNotificationCallback(this);

        if (SUCCEEDED(hr)) {
            hr = AttachDevice();
        }
    }

    return hr;
}

HRESULT CoreAudio::Init(std::wstring deviceId) {
    _devId = deviceId;
    return Init();
}

void CoreAudio::Dispose() {
    DetachDevice();
    _devEnumerator->UnregisterEndpointNotificationCallback(this);
}

HRESULT CoreAudio::AttachDevice() {
    HRESULT hr;

    if (_devId.empty()) {
        /* Use default device */
        hr = _devEnumerator->GetDefaultAudioEndpoint(eRender,
            eMultimedia, &_device);
        if (SUCCEEDED(hr)) {
            LPWSTR id = NULL;
            _device->GetId(&id);
            if (id) {
                _devId = std::wstring(id);
                CoTaskMemFree(id);
            }
        }
    } else {
        hr = _devEnumerator->GetDevice(_devId.c_str(), &_device);
    }

    if (SUCCEEDED(hr)) {
        hr = _device->Activate(__uuidof(_volumeControl),
            CLSCTX_INPROC_SERVER, NULL, (void **) &_volumeControl);

        CLOG(L"Attached to audio device: [%s]", DeviceName().c_str());

        if (SUCCEEDED(hr)) {
            hr = _volumeControl->RegisterControlChangeNotify(this);
            _registeredNotifications = SUCCEEDED(hr);
        }
    } else {
        CLOG(L"Failed to find audio device!");
    }

    return hr;
}

void CoreAudio::DetachDevice() {
    if (_volumeControl != NULL) {

        if (_registeredNotifications) {
            _volumeControl->UnregisterControlChangeNotify(this);
            _registeredNotifications = false;
        }

        _volumeControl->Release();
    }

    if (_device != NULL) {
        _device->Release();
    }
}

HRESULT CoreAudio::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) {
    if (pNotify->guidEventContext == G3RVXCoreAudioEvent) {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, (WPARAM) 1, NULL);
    } else {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, NULL, NULL);
    }

    return S_OK;
}

HRESULT CoreAudio::OnDefaultDeviceChanged(
    EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) {
    if (flow == eRender) {
        PostMessage(_notifyHwnd, MSG_VOL_DEVCHNG, 0, 0);
    }

    return S_OK;
}

HRESULT CoreAudio::SelectDevice(std::wstring deviceId) {
    HRESULT hr;
    _devId = deviceId;
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

HRESULT CoreAudio::SelectDefaultDevice() {
    HRESULT hr;
    _devId = L"";
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

std::list<VolumeController::DeviceInfo> CoreAudio::ListDevices() {
    std::list<VolumeController::DeviceInfo> devList;
    IMMDeviceCollection *devices = NULL;

    HRESULT hr = _devEnumerator->EnumAudioEndpoints(
        eRender,
        DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED,
        &devices);

    if (FAILED(hr)) {
        if (devices) {
            devices->Release();
        }
        return devList;
    }

    UINT numDevices = 0;
    devices->GetCount(&numDevices);
    LPWSTR devId;
    for (unsigned int i = 0; i < numDevices; ++i) {
        IMMDevice *device = NULL;
        HRESULT hr = devices->Item(i, &device);
        if (FAILED(hr)) {
            if (device) {
                device->Release();
            }

            continue;
        }

        device->GetId(&devId);
        std::wstring idStr;
        if (devId) {
            idStr = std::wstring(devId);
            CoTaskMemFree(devId);
        } else {
            continue;
        }
        VolumeController::DeviceInfo devInfo = {};
        devInfo.id = idStr;
        devInfo.name = DeviceName(idStr);
        devList.push_back(devInfo);
        device->Release();
    }

    devices->Release();
    return devList;
}

std::wstring CoreAudio::DeviceId() {
    return _devId;
}

std::wstring CoreAudio::DeviceName() {
    return DeviceName(_device);
}

std::wstring CoreAudio::DeviceDesc() {
    return DeviceDesc(_device);
}

std::wstring CoreAudio::DeviceName(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceDesc(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceName(IMMDevice *device) {
    if (device == NULL) {
        return L"";
    }

    IPropertyStore *props = NULL;
    HRESULT hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvName;
    PropVariantInit(&pvName);
    props->GetValue(PKEY_Device_FriendlyName, &pvName);

    std::wstring str(pvName.pwszVal);
    PropVariantClear(&pvName);
    props->Release();

    return str;
}

std::wstring CoreAudio::DeviceDesc(IMMDevice *device) {
    if (device == NULL) {
        return L"";
    }

    IPropertyStore *props = NULL;
    HRESULT hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvDesc;
    PropVariantInit(&pvDesc);
    props->GetValue(PKEY_Device_DeviceDesc, &pvDesc);

    std::wstring str(pvDesc.pwszVal);
    PropVariantClear(&pvDesc);
    props->Release();

    return str;
}

float CoreAudio::Volume() {
    float vol = 0.0f;
    if (_volumeControl) {
        _volumeControl->GetMasterVolumeLevelScalar(&vol);
    }
    return vol;
}

void CoreAudio::Volume(float vol) {
    if (vol > 1.0f) {
        vol = 1.0f;
    }

    if (vol < 0.0f) {
        vol = 0.0f;
    }

    if (_volumeControl) {
        _volumeControl->SetMasterVolumeLevelScalar(vol, &G3RVXCoreAudioEvent);
    }
}

bool CoreAudio::Muted() {
    if (_volumeControl == NULL) {
        return true;
    }

    BOOL muted = FALSE;
    _volumeControl->GetMute(&muted);

    return (muted == TRUE) ? true : false;
}

void CoreAudio::Muted(bool muted) {
    if (_volumeControl) {
        _volumeControl->SetMute(muted, &G3RVXCoreAudioEvent);
    }
}

ULONG CoreAudio::AddRef() {
    return InterlockedIncrement(&_refCount);
}

ULONG CoreAudio::Release() {
    long lRef = InterlockedDecrement(&_refCount);
    if (lRef == 0) {
        delete this;
    }
    return lRef;
}

HRESULT CoreAudio::QueryInterface(REFIID iid, void **ppUnk) {
    if ((iid == __uuidof(IUnknown)) ||
        (iid == __uuidof(IMMNotificationClient))) {
        *ppUnk = static_cast<IMMNotificationClient*>(this);
    } else if (iid == __uuidof(IAudioEndpointVolumeCallback)) {
        *ppUnk = static_cast<IAudioEndpointVolumeCallback*>(this);
    } else {
        *ppUnk = NULL;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}<commit_msg>Add missing checks for function results<commit_after>#include "CoreAudio.h"
#include "Functiondiscoverykeys_devpkey.h"
#include "../../Logger.h"

// {EC9CB649-7E84-4B42-B367-7FC39BE17806}
static const GUID G3RVXCoreAudioEvent = { 0xec9cb649, 0x7e84, 0x4b42,
    { 0xb3, 0x67, 0x7f, 0xc3, 0x9b, 0xe1, 0x78, 0x6 } };

HRESULT CoreAudio::Init() {
    HRESULT hr;

    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator),
        NULL,
        CLSCTX_INPROC_SERVER,
        IID_PPV_ARGS(&_devEnumerator));

    if (SUCCEEDED(hr)) {
        hr = _devEnumerator->RegisterEndpointNotificationCallback(this);

        if (SUCCEEDED(hr)) {
            hr = AttachDevice();
        }
    }

    return hr;
}

HRESULT CoreAudio::Init(std::wstring deviceId) {
    _devId = deviceId;
    return Init();
}

void CoreAudio::Dispose() {
    DetachDevice();
    _devEnumerator->UnregisterEndpointNotificationCallback(this);
}

HRESULT CoreAudio::AttachDevice() {
    HRESULT hr;

    if (_devId.empty()) {
        /* Use default device */
        hr = _devEnumerator->GetDefaultAudioEndpoint(eRender,
            eMultimedia, &_device);
        if (SUCCEEDED(hr)) {
            LPWSTR id = NULL;
            hr = _device->GetId(&id);
            if (SUCCEEDED(hr) && id) {
                _devId = std::wstring(id);
                CoTaskMemFree(id);
            }
        }
    } else {
        hr = _devEnumerator->GetDevice(_devId.c_str(), &_device);
    }

    if (SUCCEEDED(hr)) {
        hr = _device->Activate(__uuidof(_volumeControl),
            CLSCTX_INPROC_SERVER, NULL, (void **) &_volumeControl);

        CLOG(L"Attached to audio device: [%s]", DeviceName().c_str());

        if (SUCCEEDED(hr)) {
            hr = _volumeControl->RegisterControlChangeNotify(this);
            _registeredNotifications = SUCCEEDED(hr);
        }
    } else {
        CLOG(L"Failed to find audio device!");
    }

    return hr;
}

void CoreAudio::DetachDevice() {
    if (_volumeControl != NULL) {

        if (_registeredNotifications) {
            _volumeControl->UnregisterControlChangeNotify(this);
            _registeredNotifications = false;
        }

        _volumeControl->Release();
    }

    if (_device != NULL) {
        _device->Release();
    }
}

HRESULT CoreAudio::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) {
    if (pNotify->guidEventContext == G3RVXCoreAudioEvent) {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, (WPARAM) 1, NULL);
    } else {
        PostMessage(_notifyHwnd, MSG_VOL_CHNG, NULL, NULL);
    }

    return S_OK;
}

HRESULT CoreAudio::OnDefaultDeviceChanged(
    EDataFlow flow, ERole role, LPCWSTR pwstrDefaultDeviceId) {
    if (flow == eRender) {
        PostMessage(_notifyHwnd, MSG_VOL_DEVCHNG, 0, 0);
    }

    return S_OK;
}

HRESULT CoreAudio::SelectDevice(std::wstring deviceId) {
    HRESULT hr;
    _devId = deviceId;
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

HRESULT CoreAudio::SelectDefaultDevice() {
    HRESULT hr;
    _devId = L"";
    DetachDevice();
    hr = AttachDevice();
    return hr;
}

std::list<VolumeController::DeviceInfo> CoreAudio::ListDevices() {
    std::list<VolumeController::DeviceInfo> devList;
    IMMDeviceCollection *devices = NULL;

    HRESULT hr = _devEnumerator->EnumAudioEndpoints(
        eRender,
        DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED,
        &devices);

    if (FAILED(hr)) {
        return devList;
    }

    UINT numDevices = 0;
    hr = devices->GetCount(&numDevices);
    if (FAILED(hr)) {
        return devList;
    }
    LPWSTR devId;
    for (unsigned int i = 0; i < numDevices; ++i) {
        IMMDevice *device = NULL;
        HRESULT hr = devices->Item(i, &device);
        if (FAILED(hr)) {
            continue;
        }

        hr = device->GetId(&devId);
        if (FAILED(hr)) {
            device->Release();
            continue;
        }

        std::wstring idStr;
        if (devId) {
            idStr = std::wstring(devId);
            CoTaskMemFree(devId);
        } else {
            continue;
        }

        VolumeController::DeviceInfo devInfo = {};
        devInfo.id = idStr;
        devInfo.name = DeviceName(idStr);
        devList.push_back(devInfo);
        device->Release();
    }

    devices->Release();
    return devList;
}

std::wstring CoreAudio::DeviceId() {
    return _devId;
}

std::wstring CoreAudio::DeviceName() {
    return DeviceName(_device);
}

std::wstring CoreAudio::DeviceDesc() {
    return DeviceDesc(_device);
}

std::wstring CoreAudio::DeviceName(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceDesc(std::wstring deviceId) {
    IMMDevice *device;
    HRESULT hr = _devEnumerator->GetDevice(deviceId.c_str(), &device);
    if (FAILED(hr)) {
        return L"";
    }
    std::wstring name = DeviceName(device);
    device->Release();
    return name;
}

std::wstring CoreAudio::DeviceName(IMMDevice *device) {
    if (device == NULL) {
        return L"";
    }

    IPropertyStore *props = NULL;
    HRESULT hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvName;
    PropVariantInit(&pvName);
    hr = props->GetValue(PKEY_Device_FriendlyName, &pvName);
    if (FAILED(hr)) {
        props->Release();
        return L"";
    }

    std::wstring str(pvName.pwszVal);
    PropVariantClear(&pvName);
    props->Release();

    return str;
}

std::wstring CoreAudio::DeviceDesc(IMMDevice *device) {
    HRESULT hr;

    if (device == NULL) {
        return L"";
    }

    IPropertyStore *props = NULL;
    hr = device->OpenPropertyStore(STGM_READ, &props);
    if (FAILED(hr)) {
        return L"";
    }

    PROPVARIANT pvDesc;
    PropVariantInit(&pvDesc);
    hr = props->GetValue(PKEY_Device_DeviceDesc, &pvDesc);
    if (FAILED(hr)) {
        props->Release();
        return L"";
    }

    std::wstring str(pvDesc.pwszVal);
    PropVariantClear(&pvDesc);
    props->Release();
    return str;
}

float CoreAudio::Volume() {
    float vol = 0.0f;
    if (_volumeControl) {
        HRESULT hr = _volumeControl->GetMasterVolumeLevelScalar(&vol);
        if (FAILED(hr)) {
            return 0;
        }
    }
    return vol;
}

void CoreAudio::Volume(float vol) {
    if (vol > 1.0f) {
        vol = 1.0f;
    }

    if (vol < 0.0f) {
        vol = 0.0f;
    }

    if (_volumeControl) {
        _volumeControl->SetMasterVolumeLevelScalar(vol, &G3RVXCoreAudioEvent);
    }
}

bool CoreAudio::Muted() {
    if (_volumeControl == NULL) {
        return true;
    }

    BOOL muted = FALSE;
    HRESULT hr = _volumeControl->GetMute(&muted);
    if (FAILED(hr)) {
        return false;
    }

    return (muted == TRUE) ? true : false;
}

void CoreAudio::Muted(bool muted) {
    if (_volumeControl) {
        _volumeControl->SetMute(muted, &G3RVXCoreAudioEvent);
    }
}

ULONG CoreAudio::AddRef() {
    return InterlockedIncrement(&_refCount);
}

ULONG CoreAudio::Release() {
    long lRef = InterlockedDecrement(&_refCount);
    if (lRef == 0) {
        delete this;
    }
    return lRef;
}

HRESULT CoreAudio::QueryInterface(REFIID iid, void **ppUnk) {
    if ((iid == __uuidof(IUnknown)) ||
        (iid == __uuidof(IMMNotificationClient))) {
        *ppUnk = static_cast<IMMNotificationClient*>(this);
    } else if (iid == __uuidof(IAudioEndpointVolumeCallback)) {
        *ppUnk = static_cast<IAudioEndpointVolumeCallback*>(this);
    } else {
        *ppUnk = NULL;
        return E_NOINTERFACE;
    }

    AddRef();
    return S_OK;
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012, 2014 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 *          Steve Reinhardt
 *          Andreas Hansson
 */

#ifndef __BASE_ADDR_RANGE_HH__
#define __BASE_ADDR_RANGE_HH__

#include <list>
#include <vector>

#include "base/bitfield.hh"
#include "base/cprintf.hh"
#include "base/misc.hh"
#include "base/types.hh"

/**
 * The AddrRange class encapsulates an address range, and supports a
 * number of tests to check if two ranges intersect, if a range
 * contains a specific address etc. Besides a basic range, the
 * AddrRange also support interleaved ranges, to stripe across cache
 * banks, or memory controllers. The interleaving is implemented by
 * allowing a number of bits of the address, at an arbitrary bit
 * position, to be used as interleaving bits with an associated
 * matching value. In addition, to prevent uniformly strided address
 * patterns from a very biased interleaving, we also allow basic
 * XOR-based hashing by specifying an additional set of bits to XOR
 * with before matching.
 *
 * The AddrRange is also able to coalesce a number of interleaved
 * ranges to a contiguous range.
 */
class AddrRange
{

  private:

    /// Private fields for the start and end of the range
    /// Both _start and _end are part of the range.
    Addr _start;
    Addr _end;

    /// The high bit of the slice that is used for interleaving
    uint8_t intlvHighBit;

    /// The high bit of the slice used to XOR hash the value we match
    /// against, set to 0 to disable.
    uint8_t xorHighBit;

    /// The number of bits used for interleaving, set to 0 to disable
    uint8_t intlvBits;

    /// The value to compare the slice addr[high:(high - bits + 1)]
    /// with.
    uint8_t intlvMatch;

  public:

    AddrRange()
        : _start(1), _end(0), intlvHighBit(0), xorHighBit(0), intlvBits(0),
          intlvMatch(0)
    {}

    AddrRange(Addr _start, Addr _end, uint8_t _intlv_high_bit,
              uint8_t _xor_high_bit, uint8_t _intlv_bits,
              uint8_t _intlv_match)
        : _start(_start), _end(_end), intlvHighBit(_intlv_high_bit),
          xorHighBit(_xor_high_bit), intlvBits(_intlv_bits),
          intlvMatch(_intlv_match)
    {
        // sanity checks
        fatal_if(intlvBits && intlvMatch >= ULL(1) << intlvBits,
                 "Match value %d does not fit in %d interleaving bits\n",
                 intlvMatch, intlvBits);

        // ignore the XOR bits if not interleaving
        if (intlvBits && xorHighBit) {
            if (xorHighBit == intlvHighBit) {
                fatal("XOR and interleave high bit must be different\n");
            }  else if (xorHighBit > intlvHighBit) {
                if ((xorHighBit - intlvHighBit) < intlvBits)
                    fatal("XOR and interleave high bit must be at least "
                          "%d bits apart\n", intlvBits);
            } else {
                if ((intlvHighBit - xorHighBit) < intlvBits) {
                    fatal("Interleave and XOR high bit must be at least "
                          "%d bits apart\n", intlvBits);
                }
            }
        }
    }

    AddrRange(Addr _start, Addr _end)
        : _start(_start), _end(_end), intlvHighBit(0), xorHighBit(0),
          intlvBits(0), intlvMatch(0)
    {}

    /**
     * Create an address range by merging a collection of interleaved
     * ranges.
     *
     * @param ranges Interleaved ranges to be merged
     */
    AddrRange(const std::vector<AddrRange>& ranges)
        : _start(1), _end(0), intlvHighBit(0), xorHighBit(0), intlvBits(0),
          intlvMatch(0)
    {
        if (!ranges.empty()) {
            // get the values from the first one and check the others
            _start = ranges.front()._start;
            _end = ranges.front()._end;
            intlvHighBit = ranges.front().intlvHighBit;
            xorHighBit = ranges.front().xorHighBit;
            intlvBits = ranges.front().intlvBits;

            if (ranges.size() != (ULL(1) << intlvBits))
                fatal("Got %d ranges spanning %d interleaving bits\n",
                      ranges.size(), intlvBits);

            uint8_t match = 0;
            for (const auto& r : ranges) {
                if (!mergesWith(r))
                    fatal("Can only merge ranges with the same start, end "
                          "and interleaving bits\n");

                if (r.intlvMatch != match)
                    fatal("Expected interleave match %d but got %d when "
                          "merging\n", match, r.intlvMatch);
                ++match;
            }

            // our range is complete and we can turn this into a
            // non-interleaved range
            intlvHighBit = 0;
            xorHighBit = 0;
            intlvBits = 0;
        }
    }

    /**
     * Determine if the range is interleaved or not.
     *
     * @return true if interleaved
     */
    bool interleaved() const { return intlvBits != 0; }

    /**
     * Determine if the range interleaving is hashed or not.
     */
    bool hashed() const { return interleaved() && xorHighBit != 0; }

    /**
     * Determing the interleaving granularity of the range.
     *
     * @return The size of the regions created by the interleaving bits
     */
    uint64_t granularity() const
    {
        return ULL(1) << (intlvHighBit - intlvBits + 1);
    }

    /**
     * Determine the number of interleaved address stripes this range
     * is part of.
     *
     * @return The number of stripes spanned by the interleaving bits
     */
    uint32_t stripes() const { return ULL(1) << intlvBits; }

    /**
     * Get the size of the address range. For a case where
     * interleaving is used we make the simplifying assumption that
     * the size is a divisible by the size of the interleaving slice.
     */
    Addr size() const
    {
        return (_end - _start + 1) >> intlvBits;
    }

    /**
     * Determine if the range is valid.
     */
    bool valid() const { return _start <= _end; }

    /**
     * Get the start address of the range.
     */
    Addr start() const { return _start; }

    /**
     * Get a string representation of the range. This could
     * alternatively be implemented as a operator<<, but at the moment
     * that seems like overkill.
     */
    std::string to_string() const
    {
        if (interleaved()) {
            if (hashed()) {
                return csprintf("[%#llx : %#llx], [%d : %d] XOR [%d : %d] = %d",
                                _start, _end,
                                intlvHighBit, intlvHighBit - intlvBits + 1,
                                xorHighBit, xorHighBit - intlvBits + 1,
                                intlvMatch);
            } else {
                return csprintf("[%#llx : %#llx], [%d : %d] = %d",
                                _start, _end,
                                intlvHighBit, intlvHighBit - intlvBits + 1,
                                intlvMatch);
            }
        } else {
            return csprintf("[%#llx : %#llx]", _start, _end);
        }
    }

    /**
     * Determine if another range merges with the current one, i.e. if
     * they are part of the same contigous range and have the same
     * interleaving bits.
     *
     * @param r Range to evaluate merging with
     * @return true if the two ranges would merge
     */
    bool mergesWith(const AddrRange& r) const
    {
        return r._start == _start && r._end == _end &&
            r.intlvHighBit == intlvHighBit &&
            r.xorHighBit == xorHighBit &&
            r.intlvBits == intlvBits;
    }

    /**
     * Determine if another range intersects this one, i.e. if there
     * is an address that is both in this range and the other
     * range. No check is made to ensure either range is valid.
     *
     * @param r Range to intersect with
     * @return true if the intersection of the two ranges is not empty
     */
    bool intersects(const AddrRange& r) const
    {
        if (!interleaved()) {
            return _start <= r._end && _end >= r._start;
        }

        // the current range is interleaved, split the check up in
        // three cases
        if (r.size() == 1)
            // keep it simple and check if the address is within
            // this range
            return contains(r.start());
        else if (!r.interleaved())
            // be conservative and ignore the interleaving
            return _start <= r._end && _end >= r._start;
        else if (mergesWith(r))
            // restrict the check to ranges that belong to the
            // same chunk
            return intlvMatch == r.intlvMatch;
        else
            panic("Cannot test intersection of interleaved range %s\n",
                  to_string());
    }

    /**
     * Determine if this range is a subset of another range, i.e. if
     * every address in this range is also in the other range. No
     * check is made to ensure either range is valid.
     *
     * @param r Range to compare with
     * @return true if the this range is a subset of the other one
     */
    bool isSubset(const AddrRange& r) const
    {
        if (interleaved())
            panic("Cannot test subset of interleaved range %s\n", to_string());
        return _start >= r._start && _end <= r._end;
    }

    /**
     * Determine if the range contains an address.
     *
     * @param a Address to compare with
     * @return true if the address is in the range
     */
    bool contains(const Addr& a) const
    {
        // check if the address is in the range and if there is either
        // no interleaving, or with interleaving also if the selected
        // bits from the address match the interleaving value
        bool in_range = a >= _start && a <= _end;
        if (!interleaved()) {
            return in_range;
        } else if (in_range) {
            if (!hashed()) {
                return bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ==
                    intlvMatch;
            } else {
                return (bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ^
                        bits(a, xorHighBit, xorHighBit - intlvBits + 1)) ==
                    intlvMatch;
            }
        }
        return false;
    }

/**
 * Keep the operators away from SWIG.
 */
#ifndef SWIG

    /**
     * Less-than operator used to turn an STL map into a binary search
     * tree of non-overlapping address ranges.
     *
     * @param r Range to compare with
     * @return true if the start address is less than that of the other range
     */
    bool operator<(const AddrRange& r) const
    {
        if (_start != r._start)
            return _start < r._start;
        else
            // for now assume that the end is also the same, and that
            // we are looking at the same interleaving bits
            return intlvMatch < r.intlvMatch;
    }

#endif // SWIG
};

/**
 * Convenience typedef for a collection of address ranges
 */
typedef std::list<AddrRange> AddrRangeList;

inline AddrRange
RangeEx(Addr start, Addr end)
{ return AddrRange(start, end - 1); }

inline AddrRange
RangeIn(Addr start, Addr end)
{ return AddrRange(start, end); }

inline AddrRange
RangeSize(Addr start, Addr size)
{ return AddrRange(start, start + size - 1); }

#endif // __BASE_ADDR_RANGE_HH__
<commit_msg>base: add an accessor and operators ==,!= to address ranges<commit_after>/*
 * Copyright (c) 2012, 2014 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 *          Steve Reinhardt
 *          Andreas Hansson
 */

#ifndef __BASE_ADDR_RANGE_HH__
#define __BASE_ADDR_RANGE_HH__

#include <list>
#include <vector>

#include "base/bitfield.hh"
#include "base/cprintf.hh"
#include "base/misc.hh"
#include "base/types.hh"

/**
 * The AddrRange class encapsulates an address range, and supports a
 * number of tests to check if two ranges intersect, if a range
 * contains a specific address etc. Besides a basic range, the
 * AddrRange also support interleaved ranges, to stripe across cache
 * banks, or memory controllers. The interleaving is implemented by
 * allowing a number of bits of the address, at an arbitrary bit
 * position, to be used as interleaving bits with an associated
 * matching value. In addition, to prevent uniformly strided address
 * patterns from a very biased interleaving, we also allow basic
 * XOR-based hashing by specifying an additional set of bits to XOR
 * with before matching.
 *
 * The AddrRange is also able to coalesce a number of interleaved
 * ranges to a contiguous range.
 */
class AddrRange
{

  private:

    /// Private fields for the start and end of the range
    /// Both _start and _end are part of the range.
    Addr _start;
    Addr _end;

    /// The high bit of the slice that is used for interleaving
    uint8_t intlvHighBit;

    /// The high bit of the slice used to XOR hash the value we match
    /// against, set to 0 to disable.
    uint8_t xorHighBit;

    /// The number of bits used for interleaving, set to 0 to disable
    uint8_t intlvBits;

    /// The value to compare the slice addr[high:(high - bits + 1)]
    /// with.
    uint8_t intlvMatch;

  public:

    AddrRange()
        : _start(1), _end(0), intlvHighBit(0), xorHighBit(0), intlvBits(0),
          intlvMatch(0)
    {}

    AddrRange(Addr _start, Addr _end, uint8_t _intlv_high_bit,
              uint8_t _xor_high_bit, uint8_t _intlv_bits,
              uint8_t _intlv_match)
        : _start(_start), _end(_end), intlvHighBit(_intlv_high_bit),
          xorHighBit(_xor_high_bit), intlvBits(_intlv_bits),
          intlvMatch(_intlv_match)
    {
        // sanity checks
        fatal_if(intlvBits && intlvMatch >= ULL(1) << intlvBits,
                 "Match value %d does not fit in %d interleaving bits\n",
                 intlvMatch, intlvBits);

        // ignore the XOR bits if not interleaving
        if (intlvBits && xorHighBit) {
            if (xorHighBit == intlvHighBit) {
                fatal("XOR and interleave high bit must be different\n");
            }  else if (xorHighBit > intlvHighBit) {
                if ((xorHighBit - intlvHighBit) < intlvBits)
                    fatal("XOR and interleave high bit must be at least "
                          "%d bits apart\n", intlvBits);
            } else {
                if ((intlvHighBit - xorHighBit) < intlvBits) {
                    fatal("Interleave and XOR high bit must be at least "
                          "%d bits apart\n", intlvBits);
                }
            }
        }
    }

    AddrRange(Addr _start, Addr _end)
        : _start(_start), _end(_end), intlvHighBit(0), xorHighBit(0),
          intlvBits(0), intlvMatch(0)
    {}

    /**
     * Create an address range by merging a collection of interleaved
     * ranges.
     *
     * @param ranges Interleaved ranges to be merged
     */
    AddrRange(const std::vector<AddrRange>& ranges)
        : _start(1), _end(0), intlvHighBit(0), xorHighBit(0), intlvBits(0),
          intlvMatch(0)
    {
        if (!ranges.empty()) {
            // get the values from the first one and check the others
            _start = ranges.front()._start;
            _end = ranges.front()._end;
            intlvHighBit = ranges.front().intlvHighBit;
            xorHighBit = ranges.front().xorHighBit;
            intlvBits = ranges.front().intlvBits;

            if (ranges.size() != (ULL(1) << intlvBits))
                fatal("Got %d ranges spanning %d interleaving bits\n",
                      ranges.size(), intlvBits);

            uint8_t match = 0;
            for (const auto& r : ranges) {
                if (!mergesWith(r))
                    fatal("Can only merge ranges with the same start, end "
                          "and interleaving bits\n");

                if (r.intlvMatch != match)
                    fatal("Expected interleave match %d but got %d when "
                          "merging\n", match, r.intlvMatch);
                ++match;
            }

            // our range is complete and we can turn this into a
            // non-interleaved range
            intlvHighBit = 0;
            xorHighBit = 0;
            intlvBits = 0;
        }
    }

    /**
     * Determine if the range is interleaved or not.
     *
     * @return true if interleaved
     */
    bool interleaved() const { return intlvBits != 0; }

    /**
     * Determine if the range interleaving is hashed or not.
     */
    bool hashed() const { return interleaved() && xorHighBit != 0; }

    /**
     * Determing the interleaving granularity of the range.
     *
     * @return The size of the regions created by the interleaving bits
     */
    uint64_t granularity() const
    {
        return ULL(1) << (intlvHighBit - intlvBits + 1);
    }

    /**
     * Determine the number of interleaved address stripes this range
     * is part of.
     *
     * @return The number of stripes spanned by the interleaving bits
     */
    uint32_t stripes() const { return ULL(1) << intlvBits; }

    /**
     * Get the size of the address range. For a case where
     * interleaving is used we make the simplifying assumption that
     * the size is a divisible by the size of the interleaving slice.
     */
    Addr size() const
    {
        return (_end - _start + 1) >> intlvBits;
    }

    /**
     * Determine if the range is valid.
     */
    bool valid() const { return _start <= _end; }

    /**
     * Get the start address of the range.
     */
    Addr start() const { return _start; }

    /**
     * Get the end address of the range.
     */
    Addr end() const { return _end; }

    /**
     * Get a string representation of the range. This could
     * alternatively be implemented as a operator<<, but at the moment
     * that seems like overkill.
     */
    std::string to_string() const
    {
        if (interleaved()) {
            if (hashed()) {
                return csprintf("[%#llx : %#llx], [%d : %d] XOR [%d : %d] = %d",
                                _start, _end,
                                intlvHighBit, intlvHighBit - intlvBits + 1,
                                xorHighBit, xorHighBit - intlvBits + 1,
                                intlvMatch);
            } else {
                return csprintf("[%#llx : %#llx], [%d : %d] = %d",
                                _start, _end,
                                intlvHighBit, intlvHighBit - intlvBits + 1,
                                intlvMatch);
            }
        } else {
            return csprintf("[%#llx : %#llx]", _start, _end);
        }
    }

    /**
     * Determine if another range merges with the current one, i.e. if
     * they are part of the same contigous range and have the same
     * interleaving bits.
     *
     * @param r Range to evaluate merging with
     * @return true if the two ranges would merge
     */
    bool mergesWith(const AddrRange& r) const
    {
        return r._start == _start && r._end == _end &&
            r.intlvHighBit == intlvHighBit &&
            r.xorHighBit == xorHighBit &&
            r.intlvBits == intlvBits;
    }

    /**
     * Determine if another range intersects this one, i.e. if there
     * is an address that is both in this range and the other
     * range. No check is made to ensure either range is valid.
     *
     * @param r Range to intersect with
     * @return true if the intersection of the two ranges is not empty
     */
    bool intersects(const AddrRange& r) const
    {
        if (!interleaved()) {
            return _start <= r._end && _end >= r._start;
        }

        // the current range is interleaved, split the check up in
        // three cases
        if (r.size() == 1)
            // keep it simple and check if the address is within
            // this range
            return contains(r.start());
        else if (!r.interleaved())
            // be conservative and ignore the interleaving
            return _start <= r._end && _end >= r._start;
        else if (mergesWith(r))
            // restrict the check to ranges that belong to the
            // same chunk
            return intlvMatch == r.intlvMatch;
        else
            panic("Cannot test intersection of interleaved range %s\n",
                  to_string());
    }

    /**
     * Determine if this range is a subset of another range, i.e. if
     * every address in this range is also in the other range. No
     * check is made to ensure either range is valid.
     *
     * @param r Range to compare with
     * @return true if the this range is a subset of the other one
     */
    bool isSubset(const AddrRange& r) const
    {
        if (interleaved())
            panic("Cannot test subset of interleaved range %s\n", to_string());
        return _start >= r._start && _end <= r._end;
    }

    /**
     * Determine if the range contains an address.
     *
     * @param a Address to compare with
     * @return true if the address is in the range
     */
    bool contains(const Addr& a) const
    {
        // check if the address is in the range and if there is either
        // no interleaving, or with interleaving also if the selected
        // bits from the address match the interleaving value
        bool in_range = a >= _start && a <= _end;
        if (!interleaved()) {
            return in_range;
        } else if (in_range) {
            if (!hashed()) {
                return bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ==
                    intlvMatch;
            } else {
                return (bits(a, intlvHighBit, intlvHighBit - intlvBits + 1) ^
                        bits(a, xorHighBit, xorHighBit - intlvBits + 1)) ==
                    intlvMatch;
            }
        }
        return false;
    }

/**
 * Keep the operators away from SWIG.
 */
#ifndef SWIG

    /**
     * Less-than operator used to turn an STL map into a binary search
     * tree of non-overlapping address ranges.
     *
     * @param r Range to compare with
     * @return true if the start address is less than that of the other range
     */
    bool operator<(const AddrRange& r) const
    {
        if (_start != r._start)
            return _start < r._start;
        else
            // for now assume that the end is also the same, and that
            // we are looking at the same interleaving bits
            return intlvMatch < r.intlvMatch;
    }

    bool operator==(const AddrRange& r) const
    {
        if (_start    != r._start)    return false;
        if (_end      != r._end)      return false;
        if (intlvBits != r.intlvBits) return false;
        if (intlvBits != 0) {
            if (intlvHighBit != r.intlvHighBit) return false;
            if (intlvMatch   != r.intlvMatch)   return false;
        }
        return true;
    }

    bool operator!=(const AddrRange& r) const
    {
        return !(*this == r);
    }
#endif // SWIG
};

/**
 * Convenience typedef for a collection of address ranges
 */
typedef std::list<AddrRange> AddrRangeList;

inline AddrRange
RangeEx(Addr start, Addr end)
{ return AddrRange(start, end - 1); }

inline AddrRange
RangeIn(Addr start, Addr end)
{ return AddrRange(start, end); }

inline AddrRange
RangeSize(Addr start, Addr size)
{ return AddrRange(start, start + size - 1); }

#endif // __BASE_ADDR_RANGE_HH__
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 */

/*
 * This code was originally written by Steve Reinhardt as part of
 * the Wisconsin Wind Tunnel simulator.  Relicensed as part of M5
 * by permission.
 */

#ifndef NO_FAST_ALLOC

#ifdef __GNUC__
#pragma implementation
#endif

#include <assert.h>
#include "base/fast_alloc.hh"

void *FastAlloc::freeLists[Num_Buckets];

#ifdef FAST_ALLOC_STATS
unsigned FastAlloc::newCount[Num_Buckets];
unsigned FastAlloc::deleteCount[Num_Buckets];
unsigned FastAlloc::allocCount[Num_Buckets];
#endif

void *FastAlloc::moreStructs(int bucket)
{
    assert(bucket > 0 && bucket < Num_Buckets);

    int sz = bucket * Alloc_Quantum;
    const int nstructs = Num_Structs_Per_New;	// how many to allocate?
    char *p = ::new char[nstructs * sz];

#ifdef FAST_ALLOC_STATS
    ++allocCount[bucket];
#endif

    freeLists[bucket] = p;
    for (int i = 0; i < (nstructs-2); ++i, p += sz)
        *(void **)p = p + sz;
    *(void **)p = 0;

    return (p + sz);
}

#ifdef FAST_ALLOC_DEBUG

#include <typeinfo>
#include <iostream>
#include <iomanip>
#include <map>
#include <string>

using namespace std;

// count of in-use FastAlloc objects
int FastAlloc::numInUse;

// dummy head & tail object for doubly linked list of in-use FastAlloc
// objects
FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead);

// special constructor for dummy head: make inUsePrev & inUseNext
// point to self
FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next)
{
    inUsePrev = prev;
    inUseNext = next;
}

// constructor: marks as in use, add to in-use list
FastAlloc::FastAlloc()
{
    // mark this object in use
    inUse = true;

    // update count
    ++numInUse;

    // add to tail of list of in-use objects ("before" dummy head)
    FastAlloc *myNext = &inUseHead;
    FastAlloc *myPrev = inUseHead.inUsePrev;

    inUsePrev = myPrev;
    inUseNext = myNext;
    myPrev->inUseNext = this;
    myNext->inUsePrev = this;
}

// destructor: mark not in use, remove from in-use list
FastAlloc::~FastAlloc()
{
    assert(inUse);
    inUse = false;

    --numInUse;
    assert(numInUse >= 0);

    // remove me from in-use list
    inUsePrev->inUseNext = inUseNext;
    inUseNext->inUsePrev = inUsePrev;
}

// summarize in-use list
void
FastAlloc::dump_summary()
{
    map<string, int> typemap;

    for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext)
    {
        ++typemap[typeid(*p).name()];
    }

    map<string, int>::const_iterator mapiter;

    cout << " count  type\n"
         << " -----  ----\n";
    for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter)
    {
        cout << setw(6) << mapiter->second << "  " << mapiter->first << endl;
    }
}

// show oldest n items on in-use list
void
FastAlloc::dump_oldest(int n)
{
    // sanity check: don't want to crash the debugger if you forget to
    // pass in a parameter
    if (n < 0 || n > numInUse)
    {
        cout << "FastAlloc::dump_oldest: bad arg " << n
             << " (" << numInUse << " objects in use" << endl;
        return;
    }

    for (FastAlloc *p = inUseHead.inUsePrev;
         p != &inUseHead && n > 0;
         p = p->inUsePrev, --n)
    {
        cout << p << " " << typeid(*p).name() << endl;
    }
}

//
// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
// gdb seems to have trouble with calling C++ functions directly.
//
fast_alloc_summary()
{
    FastAlloc::dump_summary();
}

fast_alloc_oldest(int n)
{
    FastAlloc::dump_oldest(n);
}

#endif

#endif // NO_FAST_ALLOC
<commit_msg>Make NO_FAST_ALLOC compile.<commit_after>/*
 * Copyright (c) 2000-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 */

/*
 * This code was originally written by Steve Reinhardt as part of
 * the Wisconsin Wind Tunnel simulator.  Relicensed as part of M5
 * by permission.
 */

#include <assert.h>
#include "base/fast_alloc.hh"

#if !NO_FAST_ALLOC

#ifdef __GNUC__
#pragma implementation
#endif

void *FastAlloc::freeLists[Num_Buckets];

#ifdef FAST_ALLOC_STATS
unsigned FastAlloc::newCount[Num_Buckets];
unsigned FastAlloc::deleteCount[Num_Buckets];
unsigned FastAlloc::allocCount[Num_Buckets];
#endif

void *FastAlloc::moreStructs(int bucket)
{
    assert(bucket > 0 && bucket < Num_Buckets);

    int sz = bucket * Alloc_Quantum;
    const int nstructs = Num_Structs_Per_New;	// how many to allocate?
    char *p = ::new char[nstructs * sz];

#ifdef FAST_ALLOC_STATS
    ++allocCount[bucket];
#endif

    freeLists[bucket] = p;
    for (int i = 0; i < (nstructs-2); ++i, p += sz)
        *(void **)p = p + sz;
    *(void **)p = 0;

    return (p + sz);
}

#ifdef FAST_ALLOC_DEBUG

#include <typeinfo>
#include <iostream>
#include <iomanip>
#include <map>
#include <string>

using namespace std;

// count of in-use FastAlloc objects
int FastAlloc::numInUse;

// dummy head & tail object for doubly linked list of in-use FastAlloc
// objects
FastAlloc FastAlloc::inUseHead(&FastAlloc::inUseHead, &FastAlloc::inUseHead);

// special constructor for dummy head: make inUsePrev & inUseNext
// point to self
FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next)
{
    inUsePrev = prev;
    inUseNext = next;
}

// constructor: marks as in use, add to in-use list
FastAlloc::FastAlloc()
{
    // mark this object in use
    inUse = true;

    // update count
    ++numInUse;

    // add to tail of list of in-use objects ("before" dummy head)
    FastAlloc *myNext = &inUseHead;
    FastAlloc *myPrev = inUseHead.inUsePrev;

    inUsePrev = myPrev;
    inUseNext = myNext;
    myPrev->inUseNext = this;
    myNext->inUsePrev = this;
}

// destructor: mark not in use, remove from in-use list
FastAlloc::~FastAlloc()
{
    assert(inUse);
    inUse = false;

    --numInUse;
    assert(numInUse >= 0);

    // remove me from in-use list
    inUsePrev->inUseNext = inUseNext;
    inUseNext->inUsePrev = inUsePrev;
}

// summarize in-use list
void
FastAlloc::dump_summary()
{
    map<string, int> typemap;

    for (FastAlloc *p = inUseHead.inUseNext; p != &inUseHead; p = p->inUseNext)
    {
        ++typemap[typeid(*p).name()];
    }

    map<string, int>::const_iterator mapiter;

    cout << " count  type\n"
         << " -----  ----\n";
    for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter)
    {
        cout << setw(6) << mapiter->second << "  " << mapiter->first << endl;
    }
}

// show oldest n items on in-use list
void
FastAlloc::dump_oldest(int n)
{
    // sanity check: don't want to crash the debugger if you forget to
    // pass in a parameter
    if (n < 0 || n > numInUse)
    {
        cout << "FastAlloc::dump_oldest: bad arg " << n
             << " (" << numInUse << " objects in use" << endl;
        return;
    }

    for (FastAlloc *p = inUseHead.inUsePrev;
         p != &inUseHead && n > 0;
         p = p->inUsePrev, --n)
    {
        cout << p << " " << typeid(*p).name() << endl;
    }
}

//
// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
// gdb seems to have trouble with calling C++ functions directly.
//
fast_alloc_summary()
{
    FastAlloc::dump_summary();
}

fast_alloc_oldest(int n)
{
    FastAlloc::dump_oldest(n);
}

#endif

#endif // NO_FAST_ALLOC
<|endoftext|>


<commit_before>/*
 * Copyright 2016 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

enum class repair_checksum : uint8_t {
    legacy = 0,
    streamed = 1,
};

class partition_checksum {
  std::array<uint8_t, 32> digest();
};

class repair_hash {
    uint64_t hash;
};

enum class bound_weight : int8_t {
    before_all_prefixed = -1,
    equal = 0,
    after_all_prefixed = 1,
};

enum class partition_region : uint8_t {
    partition_start,
    static_row,
    clustered,
    partition_end,
};

class position_in_partition {
    partition_region get_type();
    bound_weight get_bound_weight();
    std::optional<clustering_key_prefix> get_clustering_key_prefix();
};

struct partition_key_and_mutation_fragments {
    partition_key get_key();
    std::list<frozen_mutation_fragment> get_mutation_fragments();
};

class repair_sync_boundary {
    dht::decorated_key pk;
    position_in_partition position;
};

struct get_sync_boundary_response {
    std::optional<repair_sync_boundary> boundary;
    repair_hash row_buf_combined_csum;
    uint64_t row_buf_size;
    uint64_t new_rows_size;
    uint64_t new_rows_nr;
};
<commit_msg>idl: Add row_level_diff_detect_algorithm<commit_after>/*
 * Copyright 2016 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

enum class repair_checksum : uint8_t {
    legacy = 0,
    streamed = 1,
};

class partition_checksum {
  std::array<uint8_t, 32> digest();
};

class repair_hash {
    uint64_t hash;
};

enum class bound_weight : int8_t {
    before_all_prefixed = -1,
    equal = 0,
    after_all_prefixed = 1,
};

enum class partition_region : uint8_t {
    partition_start,
    static_row,
    clustered,
    partition_end,
};

class position_in_partition {
    partition_region get_type();
    bound_weight get_bound_weight();
    std::optional<clustering_key_prefix> get_clustering_key_prefix();
};

struct partition_key_and_mutation_fragments {
    partition_key get_key();
    std::list<frozen_mutation_fragment> get_mutation_fragments();
};

class repair_sync_boundary {
    dht::decorated_key pk;
    position_in_partition position;
};

struct get_sync_boundary_response {
    std::optional<repair_sync_boundary> boundary;
    repair_hash row_buf_combined_csum;
    uint64_t row_buf_size;
    uint64_t new_rows_size;
    uint64_t new_rows_nr;
};

enum class row_level_diff_detect_algorithm : uint8_t {
    send_full_set,
};
<|endoftext|>


<commit_before>#include "ofxLineSegmentObject.h"

ofxLineSegmentObject::ofxLineSegmentObject(int iNumVerts)
{
	lineWidth = 1.0;
	for(int i=0; i < iNumVerts; i++){
		addVertex(0,0,0);
	}

}

ofxLineSegmentObject::~ofxLineSegmentObject(){}

void ofxLineSegmentObject::render()
{
	glLineWidth(lineWidth);
	glBegin(GL_LINE_STRIP);
	for(int i=0; i < vertices.size(); i++){
		glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
	}
	glEnd();

}

void ofxLineSegmentObject::setLineWidth(float iWidth)
{
	lineWidth = iWidth;
}

void ofxLineSegmentObject::setVertexPos(int iVertNum, float iX, float iY, float iZ)
{
	if(ofInRange(iVertNum, 0, vertices.size()-1)){
		vertices[iVertNum].set(iX, iY, iZ);
	}
}

void ofxLineSegmentObject::addVertex(float iX, float iY, float iZ)
{
	vertices.push_back(ofVec3f(iX, iY, iZ));
}<commit_msg>ofxLineSegment render type<commit_after>#include "ofxLineSegmentObject.h"

ofxLineSegmentObject::ofxLineSegmentObject(int iNumVerts)
{
	lineWidth = 1.0;
	for(int i=0; i < iNumVerts; i++){
		addVertex(0,0,0);
	}

}

ofxLineSegmentObject::~ofxLineSegmentObject(){}

void ofxLineSegmentObject::render()
{
	glLineWidth(lineWidth);
	glBegin(GL_LINES);
	for(int i=0; i < vertices.size(); i++){
		glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
	}
	glEnd();

}

void ofxLineSegmentObject::setLineWidth(float iWidth)
{
	lineWidth = iWidth;
}

void ofxLineSegmentObject::setVertexPos(int iVertNum, float iX, float iY, float iZ)
{
	if(ofInRange(iVertNum, 0, vertices.size()-1)){
		vertices[iVertNum].set(iX, iY, iZ);
	}
}

void ofxLineSegmentObject::addVertex(float iX, float iY, float iZ)
{
	vertices.push_back(ofVec3f(iX, iY, iZ));
}<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include <string>
#include "pegmatite.hh"
// This is very bad style, but it's okay for a short example...
using namespace std;
using namespace pegmatite;

/**
 * The AST namespace contains the abstract syntax tree for this grammar.
 */
namespace AST
{
/**
 * The base class for expressions in our language.
 */
class Expression : public ASTContainer
{
public:
	/**
	 * Evaluate this expression.  Returns a `double` representing the result of
	 * the evaluation.
	 */
	virtual double eval() const = 0;
	/**
	 * Print the node, at the specified indent depth.
	 */
	virtual void print(int depth = 0) const = 0;
	PEGMATITE_RTTI(Expression, ASTContainer);
};

/**
 * AST node representing a number.
 */
class Number : public Expression
{
public:
	/**
	 * Construct the numerical value from the text in the input range.
	 */
	virtual void construct(const pegmatite::InputRange &r, pegmatite::ASTStack &st)
	{
		stringstream stream;
		for (char c : r)
		{
			stream << c;
		}
		stream >> value;
	}

	virtual double eval() const
	{
		return value;
	}

	virtual void print(int depth) const
	{
		cout << string(depth, '\t') << value << endl;
	}

private:
	double value;
};

/**
 * Superclass for all of the binary expressions.  Contains pointers to the left
 * and right children.  Subclasses encode the operation type.
 */
template<class func, char op>
class BinaryExpression : public Expression
{
protected:
	/**
	 * The pointers to the left and right nodes.  The `ASTPtr` class will
	 * automatically fill these in when this node is constructed, popping the
	 * two top values from the AST stack.
	 */
	ASTPtr<Expression> left, right;
public:
	double eval() const override
	{
		func f;
		return f(left->eval(), right->eval());
	}

	void print(int depth) const override
	{
		cout << string(depth, '\t') << op << endl;
		left->print(depth+1);
		right->print(depth+1);
	}
};

}

namespace Parser
{
/**
 * The (singleton) calculator grammar.
 */
struct CalculatorGrammar
{
	/**
	 * Only spaces are recognised as whitespace in this toy example.
	 */
	Rule ws     = " \t\n"_E;
	/**
	 * Digits are things in the range 0-9.
	 */
	Rule digits  = "[0-9]+"_R;
	/**
	 * Numbers are one or more digits, optionally followed by a decimal point,
	 * and one or more digits, optionally followed by an exponent (which may
	 * also be negative.
	 */
	Rule num    = digits >> -('.'_E >> digits >> -("eE"_S >> -("+-"_S) >> digits));
	/**
	 * Values are either numbers or expressions in brackets (highest precedence).
	 */
	Rule val    = num |  '(' >> expr >> ')';
	/**
	 * Multiply operations are values or multiply, or divide operations,
	 * followed by a multiply symbol, followed by a values, or multiply or
	 * divide operations.  The sides can never be add or subtract operations,
	 * because they have lower precedence and so can only be parents of
	 * multiply or divide operations (or children via parenthetical
	 * expressions), not direct children.
	 */
	Rule mul_op = mul >> '*' >> mul;
	/**
	 * Divide operations follow the same syntax as multiply.
	 */
	Rule div_op = mul >> '/' >> mul;
	/**
	 * Multiply-precedence operations are either multiply or divide operations,
	 * or simple values (numbers of parenthetical expressions).
	 */
	Rule mul    = mul_op | div_op | val;
	/**
	 * Add operations can have any expression on the left (including other add
	 * expressions), but only higher-precedence operations on the right.
	 */
	Rule add_op = expr >> '+' >> expr;
	/**
	 * Subtract operations follow the same structure as add.
	 */
	Rule sub_op = expr >> '-' >> expr;
	/**
	 * Expressions can be any of the other types.
	 */
	Rule expr   = add_op | sub_op | mul;

	/**
	 * Returns a singleton instance of this grammar.
	 */
	static const CalculatorGrammar& get()
	{
		static CalculatorGrammar g;
		return g;
	}
	private:
	/**
	 * Private constructor.  This class is immutable, and so only the `get()`
	 * method should be used to return the singleton instance.
	 */
	CalculatorGrammar() {};
};

/**
 * CalculatorParser, constructs an AST from an input string.
 */
class CalculatorParser : public ASTParserDelegate
{
	BindAST<AST::Number> num = CalculatorGrammar::get().num;
	BindAST<AST::BinaryExpression<std::plus<double>,'+'>> add = CalculatorGrammar::get().add_op;
	BindAST<AST::BinaryExpression<std::minus<double>,'-'>> sub = CalculatorGrammar::get().sub_op;
	BindAST<AST::BinaryExpression<std::multiplies<double>,'*'>> mul = CalculatorGrammar::get().mul_op;
	BindAST<AST::BinaryExpression<std::divides<double>,'/'>> div = CalculatorGrammar::get().div_op;
	public:
	const CalculatorGrammar &g = CalculatorGrammar::get();
};

}

int main()
{
	Parser::CalculatorParser p;
	for (;;)
	{
		string s;

		cout << "enter a math expression (+ - * /, floats, parentheses) or enter to exit:\n";
		getline(cin, s);
		if (s.empty()) break;

		//convert the string to input
		StringInput i(std::move(s));

		//parse
		ErrorReporter er = [](const InputRange &ir, const std::string &s)
		{
			cout << "line " << ir.start.line << ", col " << ir.finish.col << ": " << s;
		};
		unique_ptr<AST::Expression> root = 0;
		p.parse(i, p.g.expr, p.g.ws, er, root);

		//on success
		if (root)
		{
			double v = root->eval();
			cout << "success\n";
			cout << "result = " << v << endl;
			cout << "parse tree:\n";
			root->print(0);
		}

		//next input
		cout << endl;
	}
	return 0;
}
<commit_msg>We’re `using namespace std`, so delete a load of `std::`<commit_after>#include <iostream>
#include <sstream>
#include <string>
#include "pegmatite.hh"
// This is very bad style, but it's okay for a short example...
using namespace std;
using namespace pegmatite;

/**
 * The AST namespace contains the abstract syntax tree for this grammar.
 */
namespace AST
{
/**
 * The base class for expressions in our language.
 */
class Expression : public ASTContainer
{
public:
	/**
	 * Evaluate this expression.  Returns a `double` representing the result of
	 * the evaluation.
	 */
	virtual double eval() const = 0;
	/**
	 * Print the node, at the specified indent depth.
	 */
	virtual void print(int depth = 0) const = 0;
	PEGMATITE_RTTI(Expression, ASTContainer);
};

/**
 * AST node representing a number.
 */
class Number : public Expression
{
public:
	/**
	 * Construct the numerical value from the text in the input range.
	 */
	virtual void construct(const pegmatite::InputRange &r, pegmatite::ASTStack &st)
	{
		stringstream stream;
		for (char c : r)
		{
			stream << c;
		}
		stream >> value;
	}

	virtual double eval() const
	{
		return value;
	}

	virtual void print(int depth) const
	{
		cout << string(depth, '\t') << value << endl;
	}

private:
	double value;
};

/**
 * Superclass for all of the binary expressions.  Contains pointers to the left
 * and right children.  Subclasses encode the operation type.
 */
template<class func, char op>
class BinaryExpression : public Expression
{
protected:
	/**
	 * The pointers to the left and right nodes.  The `ASTPtr` class will
	 * automatically fill these in when this node is constructed, popping the
	 * two top values from the AST stack.
	 */
	ASTPtr<Expression> left, right;
public:
	double eval() const override
	{
		func f;
		return f(left->eval(), right->eval());
	}

	void print(int depth) const override
	{
		cout << string(depth, '\t') << op << endl;
		left->print(depth+1);
		right->print(depth+1);
	}
};

}

namespace Parser
{
/**
 * The (singleton) calculator grammar.
 */
struct CalculatorGrammar
{
	/**
	 * Only spaces are recognised as whitespace in this toy example.
	 */
	Rule ws     = " \t\n"_E;
	/**
	 * Digits are things in the range 0-9.
	 */
	Rule digits  = "[0-9]+"_R;
	/**
	 * Numbers are one or more digits, optionally followed by a decimal point,
	 * and one or more digits, optionally followed by an exponent (which may
	 * also be negative.
	 */
	Rule num    = digits >> -('.'_E >> digits >> -("eE"_S >> -("+-"_S) >> digits));
	/**
	 * Values are either numbers or expressions in brackets (highest precedence).
	 */
	Rule val    = num |  '(' >> expr >> ')';
	/**
	 * Multiply operations are values or multiply, or divide operations,
	 * followed by a multiply symbol, followed by a values, or multiply or
	 * divide operations.  The sides can never be add or subtract operations,
	 * because they have lower precedence and so can only be parents of
	 * multiply or divide operations (or children via parenthetical
	 * expressions), not direct children.
	 */
	Rule mul_op = mul >> '*' >> mul;
	/**
	 * Divide operations follow the same syntax as multiply.
	 */
	Rule div_op = mul >> '/' >> mul;
	/**
	 * Multiply-precedence operations are either multiply or divide operations,
	 * or simple values (numbers of parenthetical expressions).
	 */
	Rule mul    = mul_op | div_op | val;
	/**
	 * Add operations can have any expression on the left (including other add
	 * expressions), but only higher-precedence operations on the right.
	 */
	Rule add_op = expr >> '+' >> expr;
	/**
	 * Subtract operations follow the same structure as add.
	 */
	Rule sub_op = expr >> '-' >> expr;
	/**
	 * Expressions can be any of the other types.
	 */
	Rule expr   = add_op | sub_op | mul;

	/**
	 * Returns a singleton instance of this grammar.
	 */
	static const CalculatorGrammar& get()
	{
		static CalculatorGrammar g;
		return g;
	}
	private:
	/**
	 * Private constructor.  This class is immutable, and so only the `get()`
	 * method should be used to return the singleton instance.
	 */
	CalculatorGrammar() {};
};

/**
 * CalculatorParser, constructs an AST from an input string.
 */
class CalculatorParser : public ASTParserDelegate
{
	BindAST<AST::Number> num = CalculatorGrammar::get().num;
	BindAST<AST::BinaryExpression<plus<double>,'+'>> add = CalculatorGrammar::get().add_op;
	BindAST<AST::BinaryExpression<minus<double>,'-'>> sub = CalculatorGrammar::get().sub_op;
	BindAST<AST::BinaryExpression<multiplies<double>,'*'>> mul = CalculatorGrammar::get().mul_op;
	BindAST<AST::BinaryExpression<divides<double>,'/'>> div = CalculatorGrammar::get().div_op;
	public:
	const CalculatorGrammar &g = CalculatorGrammar::get();
};

}

int main()
{
	Parser::CalculatorParser p;
	for (;;)
	{
		string s;

		cout << "enter a math expression (+ - * /, floats, parentheses) or enter to exit:\n";
		getline(cin, s);
		if (s.empty()) break;

		//convert the string to input
		StringInput i(move(s));

		//parse
		ErrorReporter er = [](const InputRange &ir, const string &s)
		{
			cout << "line " << ir.start.line << ", col " << ir.finish.col << ": " << s;
		};
		unique_ptr<AST::Expression> root = 0;
		p.parse(i, p.g.expr, p.g.ws, er, root);

		//on success
		if (root)
		{
			double v = root->eval();
			cout << "success\n";
			cout << "result = " << v << endl;
			cout << "parse tree:\n";
			root->print(0);
		}

		//next input
		cout << endl;
	}
	return 0;
}
<|endoftext|>