text:
#include <cassert>
#include <cstddef>
#include <exception>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <boost/variant.hpp>

#include <windows.h>
#include <atlbase.h>
#include <atlsafe.h>
#include <comdef.h>
#include <shobjidl.h>
#include <wbemidl.h>
#include <winerror.h>

#pragma comment(lib, "wbemuuid.lib")

namespace windows {

    struct result_error : public std::runtime_error {
        using std::runtime_error::runtime_error;
    };

    template <typename T, typename Pred>
    class api_result_checker {
    public:
        api_result_checker(T& result, Pred pred)
            : m_result{result}, m_pred{pred}, m_success{m_pred(m_result)} {}

        auto result() const -> T {
            if (!success()) throw result_error{"api - access error result"};
            return m_result;
        }

        auto success() const -> bool { return m_success; }
        explicit operator bool() const { return success(); }

    private:
        T& m_result;
        Pred m_pred;
        bool m_success;
    };

    class com_result_checker {
    public:
        explicit com_result_checker(HRESULT result)
            : m_result{result}, m_success{SUCCEEDED(m_result)} {}

        auto result() const -> HRESULT {
            if (!success()) throw result_error{"COM - access error result"};
            return m_result;
        }

        auto success() const -> bool { return m_success; }
        explicit operator bool() const { return success(); }

    private:
        HRESULT m_result;
        bool m_success;
    };

    // auxilary functions
    template <typename T, typename Pred>
    auto make_api_result(T result, Pred pred) {
        return api_result_checker<T, Pred>{result, pred};
    }

    template <typename T, typename Pred>
    void check_api_result(T result, Pred pred) {
        make_api_result(result, pred).result();
    }

    auto make_com_result(HRESULT result) { return com_result_checker{result}; }

    void check_com_result(HRESULT result) { make_com_result(result).result(); }

} // namespace windows

auto VariantToString(CComVariant const& variant) -> std::wstring {
    CComVariant out;
    if (SUCCEEDED(
            VariantChangeType(&out, &variant, VARIANT_ALPHABOOL, VT_BSTR))) {
        return out.bstrVal;
    } else {
        switch (variant.vt) {
        case VT_EMPTY:
            return L"[]";

        case VT_NULL:
            return L"[null]";

        case VT_DISPATCH:
            return L"[IDispatch]";

        case VT_ERROR:
            return L"[error]";

        case VT_UNKNOWN:
            return L"[IUnknown]";

        case VT_RECORD:
            return L"[IRecordInfo]";

        case VT_BYREF:
            return L"[byref]";

        case VT_ARRAY:
            return L"[array]";

        default:
            throw std::runtime_error{"COM - unknown variant type"};
        }
    }
}

auto SafeArrayElementToVariant(SAFEARRAY* psa, LONG index) -> CComVariant {
    assert(psa->cDims == 1);
    assert(0 <= index && (index + 0U < psa->rgsabound[0].cElements));

    CComVariant out;
    VARTYPE varType = VT_EMPTY;
    windows::check_com_result(SafeArrayGetVartype(psa, &varType));
    switch (varType) {

#define CASE(VarType, Value)                                                   \
    case VarType:                                                              \
        windows::check_com_result(SafeArrayGetElement(psa, &index, &Value));   \
        out.vt = VarType;                                                      \
        break;

        CASE(VT_I1,     out.cVal)
        CASE(VT_I2,     out.iVal)
        CASE(VT_I4,     out.lVal)
        CASE(VT_INT,    out.intVal)

        CASE(VT_UI1,    out.bVal)
        CASE(VT_UI2,    out.uiVal)
        CASE(VT_UI4,    out.ulVal)
        CASE(VT_UINT,   out.uintVal)

        CASE(VT_R4,     out.fltVal)
        CASE(VT_R8,     out.dblVal)

        CASE(VT_BSTR,   out.bstrVal)

        CASE(VT_BOOL,   out.boolVal)
        CASE(VT_CY,     out.cyVal)
        CASE(VT_DATE,   out.date)
        CASE(VT_DECIMAL,    out.decVal)

        CASE(VT_VARIANT,    out)
        CASE(VT_DISPATCH,   out.pdispVal)
        CASE(VT_UNKNOWN,    out.punkVal)
        CASE(VT_RECORD,     out.pRecInfo)

        CASE(VT_ERROR,  out.scode)

#undef CASE

    default:
        throw std::runtime_error{"COM - invalid variant type in safe array"};
    }

    return out;
}

struct field_t {
    std::wstring name;
    boost::variant<CComVariant, std::vector<CComVariant>> value;
};

using row_t = std::vector<field_t>;
using table_t = std::vector<row_t>;

auto GetFieldValue(CComPtr<IWbemClassObject>& pWCO, BSTR fieldName) -> field_t {
    CComVariant variant;
    windows::check_com_result(pWCO->Get(fieldName, 0, &variant, 0, 0));

    if (variant.vt & VT_ARRAY) {
        if (variant.parray->cDims != 1)
            throw std::runtime_error{"COM - invalid safe array dimensions"};

        auto psa = variant.parray;
        std::vector<CComVariant> array;
        for (auto i = 0U; i < psa->rgsabound[0].cElements; ++i) {
            array.emplace_back(SafeArrayElementToVariant(psa, i));
        }

        return {fieldName, array};
    }

    return {fieldName, variant};
}

auto GetTable(CComPtr<IEnumWbemClassObject>& pEWCO) -> table_t {
    table_t table;

    while (pEWCO) {
        CComPtr<IWbemClassObject> pWCO = nullptr;
        ULONG returnedCount            = 0;

        windows::check_com_result(
            pEWCO->Next(WBEM_INFINITE, 1, &pWCO, &returnedCount));
        if (returnedCount == 0) break;

        SAFEARRAY* fieldNames = nullptr;
        windows::check_com_result(
            pWCO->GetNames(nullptr, WBEM_FLAG_ALWAYS, nullptr, &fieldNames));

        VARTYPE varType{};
        SafeArrayGetVartype(fieldNames, &varType);
        assert(varType == VT_BSTR);
        assert(fieldNames->cDims == 1);

        CComSafeArray<BSTR> propNames;
        propNames.Attach(fieldNames);

        auto numOfFields = propNames.GetCount();
        row_t row;
        row.reserve(numOfFields);
        for (auto i = 0U; i < numOfFields; ++i) {
            row.emplace_back(GetFieldValue(pWCO, propNames.GetAt(i)));
        }

        table.emplace_back(row);
    }

    return table;
}

struct FieldValueVisitor : public boost::static_visitor<void> {
    void operator()(CComVariant variant) const {
        std::wcout << VariantToString(variant);
    }

    void operator()(std::vector<CComVariant> const& array) const {
        std::wcout << L"[";
        for (auto const& e : array) {
            std::wcout << VariantToString(e) << L", ";
        }
        std::wcout << L"]";
    }
};

int main() {
    class tagCoInit {
        HRESULT m_result;

    public:
        tagCoInit() { m_result = CoInitialize(nullptr); }

        ~tagCoInit() {
            if (success()) CoUninitialize();
        }

        bool success() const { return SUCCEEDED(m_result); }
    } CoInit;

    try {
        if (CoInit.success()) {
            CComPtr<IWbemLocator> pWL = nullptr;
            windows::check_com_result(
                pWL.CoCreateInstance(__uuidof(WbemLocator)));

            CComPtr<IWbemServices> pWS = nullptr;
            windows::check_com_result(
                pWL->ConnectServer(bstr_t(L"//./root/cimv2"), nullptr, nullptr,
                                   nullptr, 0, nullptr, nullptr, &pWS));

            windows::check_com_result(
                CoSetProxyBlanket(pWS, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE,
                                  nullptr, RPC_C_AUTHN_LEVEL_CALL,
                                  RPC_C_IMP_LEVEL_IMPERSONATE, nullptr,
                                  EOAC_NONE));

            CComPtr<IEnumWbemClassObject> pEWCO = nullptr;
            windows::check_com_result(
                pWS->ExecQuery(bstr_t("WQL"),
                               bstr_t("SELECT * FROM Win32_CacheMemory"),
                               WBEM_FLAG_FORWARD_ONLY
                                   | WBEM_FLAG_RETURN_IMMEDIATELY,
                               nullptr, &pEWCO));

            for (auto const& row : GetTable(pEWCO)) {
                for (auto const& field : row) {
                    std::wcout << field.name << L" : ";
                    boost::apply_visitor(FieldValueVisitor{}, field.value);
                    std::wcout << L"\n";
                }
                std::wcout << L"\n";
            }
        }
    } catch (std::exception const& e) {
        std::cout << "exception : " << e.what() << '\n';
    }
}


text:
#include "ThreadSafeQueue.h"

#include <thread>

#include "gtest/gtest.h"

#include "testDirectory/testVariables/TestStrings.h"
#include <boost/optional/optional_io.hpp>

using namespace ::testing;
using namespace utils;

namespace
{

void pushElements(const std::vector<std::string>& elementsToPush, ThreadSafeQueue<std::string>& queue)
{
    for (const auto& element : elementsToPush)
    {
        queue.push(element);
    }
}

void popElement(ThreadSafeQueue<std::string>& queue)
{
    while (not queue.empty())
    {
        queue.pop();
    }
}

void popFromOneQueueAndPushToOther(ThreadSafeQueue<std::string>& inputQueue,
                                   ThreadSafeQueue<std::string>& outputQueue)
{
    while (not inputQueue.empty())
    {
        if (const auto data = inputQueue.pop())
        {
            outputQueue.push(*data);
        }
    }
}
}

class ThreadSafeQueueTest : public Test
{
public:
    const std::string element1{"element1"};
    const std::string element2{"element2"};
    const std::string element3{"element3"};
    const std::vector<std::string> elements{element1, element2, element3};
};

TEST_F(ThreadSafeQueueTest, givenInitializedQueue_shouldBeEmpty)
{
    ThreadSafeQueue<std::string> queue;

    ASSERT_TRUE(queue.empty());
}

TEST_F(ThreadSafeQueueTest, givenInitializedQueueWithElements_shouldNotBeEmpty)
{
    ThreadSafeQueue<std::string> queueWithElements{elements};

    ASSERT_FALSE(queueWithElements.empty());
}

TEST_F(ThreadSafeQueueTest, popElements_shouldReturnAllElementsFromQueueAndQueueShouldBeEmpty)
{
    ThreadSafeQueue<std::string> queueWithElements{testStrings};

    const auto data = queueWithElements.popAll();

    ASSERT_EQ(data, testStrings);
    ASSERT_TRUE(queueWithElements.empty());
}

TEST_F(ThreadSafeQueueTest, pushElementToQueue_shouldReturnSameElementWithPop)
{
    ThreadSafeQueue<std::string> queue;

    queue.push(element1);

    const auto elementFromQueue = queue.pop();
    ASSERT_EQ(elementFromQueue, element1);
}

TEST_F(ThreadSafeQueueTest, pushElementsWithMultipleThreads_shouldNotDeadlock)
{
    ThreadSafeQueue<std::string> queue;

    std::thread t1(&pushElements, testStrings, std::ref(queue));
    std::thread t2(&pushElements, testStrings, std::ref(queue));
    std::thread t3(&pushElements, testStrings, std::ref(queue));
    t1.join();
    t2.join();
    t3.join();
}

TEST_F(ThreadSafeQueueTest, popElementsWithMultipleThreads_shouldNotDeadlock)
{
    ThreadSafeQueue<std::string> queueWithElements{testStrings};

    std::thread t1(&popElement, std::ref(queueWithElements));
    std::thread t2(&popElement, std::ref(queueWithElements));
    std::thread t3(&popElement, std::ref(queueWithElements));
    t1.join();
    t2.join();
    t3.join();
}

TEST_F(ThreadSafeQueueTest, popElementsFromOneQueueAndPushToOtherQueue_shouldNotDeadlock)
{
    ThreadSafeQueue<std::string> inputQueue{testStrings};
    ThreadSafeQueue<std::string> resultQueue{};

    std::thread t1(&popFromOneQueueAndPushToOther, std::ref(inputQueue), std::ref(resultQueue));
    std::thread t2(&popFromOneQueueAndPushToOther, std::ref(inputQueue), std::ref(resultQueue));
    std::thread t3(&popFromOneQueueAndPushToOther, std::ref(inputQueue), std::ref(resultQueue));
    t1.join();
    t2.join();
    t3.join();

    const auto resultData = resultQueue.popAll();
    ASSERT_EQ(resultData.size(), testStrings.size());
}

ext: cpp

max_stars_repo_name: michalovsky/Glossary

max_issues_repo_name: michalovsky/Glossary

max_forks_repo_name: michalovsky/Glossary


text:
#ifndef BURST__ITERATOR__DETAIL__JOIN_ITERATOR_HPP
#define BURST__ITERATOR__DETAIL__JOIN_ITERATOR_HPP

#include <burst/iterator/end_tag.hpp>
#include <burst/type_traits/iterator_reference.hpp>
#include <burst/type_traits/iterator_value.hpp>
#include <burst/type_traits/range_iterator.hpp>
#include <burst/type_traits/range_reference.hpp>
#include <burst/type_traits/range_value.hpp>

#include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/iterator_facade.hpp>
#include <boost/next_prior.hpp>

#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <iterator>
#include <numeric>
#include <type_traits>
#include <utility>

namespace burst
{
    namespace detail
    {
        //!     Однопроходный итератор склейки.
        /*!
                Специализация итератора склейки для того случая, когда склеиваемые диапазоны не
            являются диапазонами произвольного доступа.
         */
        template <typename InputIterator, typename IteratorCategory>
        class join_iterator_impl:
            public boost::iterator_facade
            <
                join_iterator_impl<InputIterator, IteratorCategory>,
                range_value_t<iterator_value_t<InputIterator>>,
                boost::single_pass_traversal_tag,
                range_reference_t<iterator_value_t<InputIterator>>
            >
        {
        private:
            using outer_range_iterator = InputIterator;
            using inner_range_type = iterator_value_t<outer_range_iterator>;
            static_assert
            (
                std::is_lvalue_reference<iterator_reference_t<outer_range_iterator>>::value,
                ""
            );

            using base_type =
                boost::iterator_facade
                <
                    join_iterator_impl,
                    range_value_t<inner_range_type>,
                    boost::single_pass_traversal_tag,
                    range_reference_t<inner_range_type>
                >;

        public:
            //!     Создание итератора на начало склеенного диапазона.
            /*!
                    Принимает диапазон диапазонов, которые нужно склеить, и копирует его себе
                внутрь. Затем продвигает внешний диапазон так, чтобы поддерживался инвариант.

                    Асимптотика.

                Время: O(|R|),
                    |R| — количество склеиваемых диапазонов.

                Память: O(1).
             */
            explicit join_iterator_impl (outer_range_iterator first, outer_range_iterator last):
                m_begin(std::move(first)),
                m_end(std::move(last))
            {
                maintain_invariant();
            }

            //!     Создание итератора на конец склеенного диапазона.
            /*!
                    Принимает итератор на начала склеенного диапазона и метку, обозначающую, что
                нужно создать именно итератор-конец.
                    Ничего не делает, входные аргументы игнорирует.

                    Асимптотика.

                Время: O(1).
                Память: O(1).
             */
            join_iterator_impl (iterator::end_tag_t, const join_iterator_impl & begin):
                m_begin(begin.m_end),
                m_end(begin.m_end)
            {
            }

            join_iterator_impl () = default;

        private:
            friend class boost::iterator_core_access;

            //!     Поддержать инвариант.
            /*!
                    Инвариант состоит в том, что либо внешний диапазон пуст, либо первый из
                внутренних диапазонов непуст.

                    Асимптотика.

                Время: O(|R|),
                    |R| — количество склеиваемых диапазонов.
                    Худший случай достигается тогда, когда все внутренние диапазоны пусты.

                Память: O(1).
             */
            void maintain_invariant ()
            {
                m_begin =
                    std::find_if_not(m_begin, m_end,
                        [] (const auto & r)
                        {
                            return r.empty();
                        });
            }

            //!     Продвижение итератора на один элемент вперёд.
            /*!
                    Продвигает текущий из склеиваемых диапазонов на один элемент вперёд, а затем
                поддерживает инвариант.

                    Асимптотика.

                Время: O(|R|),
                    |R| — количество склеиваемых диапазонов.

                Память: O(1).
             */
            void increment ()
            {
                m_begin->advance_begin(1);
                maintain_invariant();
            }

        private:
            typename base_type::reference dereference () const
            {
                return m_begin->front();
            }

            bool equal (const join_iterator_impl & that) const
            {
                return
                    (this->m_begin == this->m_end && that.m_begin == that.m_end) ||
                    (this->m_begin != this->m_end && that.m_begin != that.m_end &&
                        this->m_begin == that.m_begin &&
                        this->m_begin->begin() == that.m_begin->begin());
            }

        private:
            outer_range_iterator m_begin;
            outer_range_iterator m_end;
        };

        //!     Итератор склейки произвольного доступа.
        /*!
                Специализация итератора склейки для того случая, когда склеиваемые диапазоны
            являются диапазонами произвольного доступа.
                Особенностью этой специализации является то, что склеиваемый диапазон диапазонов
            хранится в неизменном виде, а текущая позиция в склеенном диапазоне задаётся двумя
            итераторами: во внешнем и внутреннем диапазонах.
         */
        template <typename RandomAccessIterator>
        class join_iterator_impl<RandomAccessIterator, boost::random_access_traversal_tag>:
            public boost::iterator_facade
            <
                join_iterator_impl<RandomAccessIterator, boost::random_access_traversal_tag>,
                range_value_t<iterator_value_t<RandomAccessIterator>>,
                boost::random_access_traversal_tag,
                range_reference_t<iterator_value_t<RandomAccessIterator>>
            >
        {
        private:
            using outer_range_iterator = RandomAccessIterator;
            using inner_range_type = iterator_value_t<outer_range_iterator>;
            using inner_range_iterator = range_iterator_t<inner_range_type>;

            using base_type =
                boost::iterator_facade
                <
                    join_iterator_impl,
                    range_value_t<inner_range_type>,
                    boost::random_access_traversal_tag,
                    range_reference_t<inner_range_type>
                >;

        public:
            //!     Создание итератора на начало склеенного диапазона.
            /*!
                    Копирует диапазон диапазонов, а также устанавливает позиционирующие индексы в
                ноль и подсчитывает количество оставшихся элементов, равное суммарному размеру
                входных диапазонов.

                    Асимптотика.

                Время: O(|R|).
                Память: O(1).
             */
            explicit join_iterator_impl (outer_range_iterator first, outer_range_iterator last):
                m_begin(std::move(first)),
                m_end(std::move(last)),
                m_outer(m_begin != m_end ? m_begin : outer_range_iterator{}),
                m_inner(m_begin != m_end ? m_outer->begin() : inner_range_iterator{}),
                m_items_remaining{}
            {
                if (m_begin != m_end)
                {
                    m_items_remaining =
                        std::accumulate(m_begin, m_end, 0u,
                            [] (auto v, const auto & r)
                            {
                                return v + r.size();
                            });

                    maintain_invariant();
                }
            }

            //!     Создание итератора на конец склеенного диапазона.
            /*!
                    Принимает итератор на начало склеенного диапазона и метку, обозначающую, что
                нужно создать именно итератор-конец.
                    Берёт из входного итератора указатель на буфер, устанавливает индекс текущего
                диапазона на конец буфера, а индекс элемента в буфере на ноль. Также устанавливает
                счётчик оставшихся элементов в ноль.

                    Асимптотика.

                Время: O(1).
                Память: O(1).
             */
            join_iterator_impl (iterator::end_tag_t, const join_iterator_impl & begin):
                m_begin(begin.m_begin),
                m_end(begin.m_end),
                m_outer(m_begin != m_end ? m_end : outer_range_iterator{}),
                m_inner(m_begin != m_end ? boost::prior(m_end)->end() : inner_range_iterator{}),
                m_items_remaining(0)
            {
            }

            join_iterator_impl () = default;

        private:
            friend class boost::iterator_core_access;

            //!     Поддержать инвариант.
            /*!
                    Итераторы всегда установлены либо на некоторый элемент непустого диапазона,
                либо за последним элементом последнего диапазона, а именно: внешний итератор
                указывает на конец внешних диапазонов, а внутренний итератор — на конец последнего
                из внешних диапазонов.
             */
            void maintain_invariant ()
            {
                while (m_inner == m_outer->end() &&
                    ++m_outer != m_end)
                {
                    m_inner = m_outer->begin();
                }
            }

            //!     Подготовить итераторы к сдвигу назад
            /*!
                    Нужно произвести операцию, в некотором смысле обратную к `maintain_invariant`:
                    Если итераторы указывают на конец, то внешний итератор нужно сдвинуть на одну
                позицию влево. Далее нужно привести итераторы в такое положение, что будет доступен
                сдвиг хотя бы на один элемент влево (с точки зрения всего итератора склейки).
             */
            void prepare_for_decrement ()
            {
                if (m_outer == m_end)
                {
                    --m_outer;
                }
                while (m_inner == m_outer->begin())
                {
                    --m_outer;
                    m_inner = m_outer->end();
                }
            }

            //!     Продвижение итератора на несколько позиций сразу.
            /*!
                    Продвигает индекс элемента в текущем диапазоне на столько позиций из требуемого
                количества позиций, сколько позволяет размер этого диапазона. Если индекс дошёл до
                конца (или начала — в зависимости от того, в какую сторону происходит продвижение)
                текущего диапазона, и при этом пройдено не всё требуемое количество позиций, то
                переходит к следующему по порядку диапазону, смотрит, сколько можно пройти в нём и
                т.д.

                    Асимптотика.

                Время: O(|R|).
                    При коротких склеиваемых диапазонах вырождается в O(n), а при длинных,
                    наоборот, стремится к O(1).

                Память: O(1).
             */
            void advance (typename base_type::difference_type n)
            {
                m_items_remaining -= n;

                if (n > 0)
                {
                    forward(std::abs(n));
                }
                else
                {
                    backward(std::abs(n));
                }
            }

            //!     Вперёд на n элементов.
            void forward (typename base_type::difference_type n)
            {
                while (n > 0)
                {
                    auto items_remaining_in_current_range = std::distance(m_inner, m_outer->end());
                    auto items_to_scroll_in_current_range = std::min(n, items_remaining_in_current_range);
                    n -= items_to_scroll_in_current_range;
                    m_inner += items_to_scroll_in_current_range;

                    maintain_invariant();
                }
            }

            //!     Назад на n элементов.
            void backward (typename base_type::difference_type n)
            {
                while (n > 0)
                {
                    prepare_for_decrement();

                    auto items_remaining_in_current_range = std::distance(m_outer->begin(), m_inner);
                    auto items_to_scroll_in_current_range = std::min(n, items_remaining_in_current_range);
                    n -= items_to_scroll_in_current_range;
                    m_inner -= items_to_scroll_in_current_range;
                }
            }

            //!     Продвижение итератора на один элемент вперёд.
            /*!
                    Увеличивает индекс в текущем диапазоне на единицу. Если индекс попал в конец
                текущего диапазона, то увеличивает индекс в буфере диапазонов на один, а индекс
                текущего элемента устанавливает в ноль.
                    Затем поддерживает инвариант.

                    Асимптотика.

                Время: O(|R|).
                Память: O(1).
             */
            void increment ()
            {
                ++m_inner;
                maintain_invariant();
                --m_items_remaining;
            }

            //!     Продвижение итератора на один элемент назад.
            /*!
                    Аналогичен продвижению вперёд, только двигается в обратном направлении.

                    Асимптотика.

                Время: O(1).
                Память: O(1).
             */
            void decrement ()
            {
                prepare_for_decrement();
                --m_inner;
                ++m_items_remaining;
            }

        private:
            typename base_type::reference dereference () const
            {
                return *m_inner;
            }

            bool equal (const join_iterator_impl & that) const
            {
                assert(this->m_begin == that.m_begin);
                assert(this->m_end == that.m_end);
                return this->m_items_remaining == that.m_items_remaining;
            }

            typename base_type::difference_type distance_to (const join_iterator_impl & that) const
            {
                return this->m_items_remaining - that.m_items_remaining;
            }

        private:
            outer_range_iterator m_begin;
            outer_range_iterator m_end;

            outer_range_iterator m_outer;
            inner_range_iterator m_inner;

            typename base_type::difference_type m_items_remaining;
        };
    }
}

#endif // BURST__ITERATOR__DETAIL__JOIN_ITERATOR_HPP

ext: hpp

max_stars_repo_name: izvolov/thrust

max_issues_repo_name: izvolov/burst

max_forks_repo_name: izvolov/thrust


text:
// Copyright (c) 2005-2009 Jaroslav Gresula
//
// Distributed under the MIT license (See accompanying file
// LICENSE.txt or copy at http://jagpdf.org/LICENSE.txt)
//

#include "precompiled.h"
#include "resourcemanagement.h"
#include "resourcemanagementhelpers.h"
#include "resourcenames.h"
#include "colorspace.h"
#include "docwriterimpl.h"
#include "imagexobject.h"
#include "imagexobjectmask.h"
#include "graphicsstatedictonaryobject.h"
#include "fontdictionary.h"
#include "fontdescriptor.h"
#include "indirectobjectfwd.h"
#include "indirectobjectcallback.h"
#include "contentstream.h"
#include "objfmtbasic.h"
#include "defines.h"
#include "canvasimpl.h"
#include "visitornoop.h"
#include "patternimpl.h"
#include <core/jstd/transaffine.h>
#include <msg_pdflib.h>
#include <msg_jstd.h>
#include <core/jstd/optionsparser.h>
#include <resources/interfaces/imageman.h>
#include <resources/interfaces/typeman.h>
#include <resources/interfaces/imagedata.h>
#include <resources/interfaces/imagemaskdata.h>
#include <resources/interfaces/resourcectx.h>
#include <core/generic/checked_cast.h>
#include <core/generic/refcountedimpl.h>
#include <boost/mem_fn.hpp>
#include <boost/bind.hpp>
#include <boost/checked_delete.hpp>
#include <boost/scoped_ptr.hpp>

using namespace jag::jstd;
using namespace boost;

namespace jag {
namespace pdf {

// ---------------------------------------------------------------------------
//                           Function object
//

namespace
{
  enum FnSpecKeywords {
      FN_DOMAIN, FN_RANGE, FN_C0, FN_C1,
      FN_EXPONENT, FN_PS, FN_BOUNDS, FN_ENCODE };

  struct FnKeywords
      : public spirit::classic::symbols<unsigned>
  {
      FnKeywords()
      {
          add
              ("domain", FN_DOMAIN)
              ("range", FN_RANGE)
              ("c0", FN_C0)
              ("c1", FN_C1)
              ("exponent", FN_EXPONENT)
              ("func", FN_PS)
              ("bounds", FN_BOUNDS)
              ("encode", FN_ENCODE)
              ;
      }
  } g_fn_keywords;
} // anonymous namespace

//
// Represents a PDF function object
//
class FunctionObj
    : public IndirectObjectFwd
{
public:
    DEFINE_VISITABLE;
    enum FunctionType {TYPE_0 = 0,
                       TYPE_2 = 2,
                       TYPE_3 = 3,
                       TYPE_4 = 4};
    FunctionObj(DocWriterImpl &doc, Char const* spec, FunctionType fn_type,
                FunctionHandle const* funs=0, UInt nr_funs=0);

private:
    void on_before_output();
    void on_write(ObjFmt& fmt);

private:
    // all types
    FunctionType        m_fn_type;
    std::vector<Double> m_domain;
    std::vector<Double> m_range;
    DocWriterImpl&      m_doc;
    // type 2 fields
    std::vector<Double> m_c0;
    std::vector<Double> m_c1;
    int m_interpolation_exponent;
    // type 3 fields
    std::vector<FunctionHandle> m_functions;
    std::vector<Double>   m_bounds;
    std::vector<Double>   m_encode;
    std::vector<IndirectObjectRef> m_function_refs;
    // type 4 - stream
    scoped_ptr<ContentStream> m_stream;
    // all types except 4
    shared_ptr<IndirectObjectCallback> m_callback;
};

//
//
//
FunctionObj::FunctionObj(DocWriterImpl &doc, Char const* spec, FunctionType fn_type,
                         FunctionHandle const* funs, UInt nr_funs)
    : m_fn_type(fn_type)
    , m_doc(doc)
{
    JAG_PRECONDITION((fn_type != TYPE_3) || (funs && (nr_funs > 1)));
    try
    {
        ParsedResult const& p=
            parse_options(spec, ParseArgs(&g_fn_keywords));

        // parse options common for all function types
        bool domain_required = (m_fn_type == TYPE_4);

        parse_array(p, FN_DOMAIN, m_domain, !domain_required);
        parse_array(p, FN_RANGE, m_range);
        if (m_range.empty() && (m_fn_type == TYPE_0 || m_fn_type == TYPE_4))
            throw exception_invalid_value(msg_fn_range_not_set()) << JAGLOC;

        // parse options specific for the given function type
        switch(m_fn_type)
        {
        case TYPE_2: {
            parse_array(p, FN_C0, m_c0);
            parse_array(p, FN_C1, m_c1);
            std::size_t c0_len = m_c0.empty() ? 1 : m_c0.size();
            std::size_t c1_len = m_c1.empty() ? 1 : m_c1.size();
            if (c0_len != c1_len) {
                throw exception_invalid_value(msg_fn_inconsistent_c0_c1()) << JAGLOC;
            }
            m_interpolation_exponent = p.to_<int>(FN_EXPONENT, 1);
            break;
        }

        case TYPE_3:
            m_functions.resize(nr_funs);
            std::copy(funs, funs + nr_funs, m_functions.begin());
            parse_array(p, FN_BOUNDS, m_bounds, false, nr_funs - 1);
            parse_array(p, FN_ENCODE, m_encode, false, nr_funs * 2);
            break;

        case TYPE_4: {
            string_32_cow func_str(p.to_<string_32_cow>(FN_PS));
            if(func_str.empty())
            {
                throw exception_invalid_value(
                    msg_opt_not_specified()) << JAGLOC;
            }

            m_stream.reset(doc.create_content_stream().release());
            m_stream->stream().write(func_str.c_str(), func_str.size());
            break;
        }

        default:
            JAG_INTERNAL_ERROR;
        }

        if (!domain_required && m_domain.empty())
        {
            // provide common default values
            m_domain.resize(2);
            m_domain[0] = 0.0;
            m_domain[1] = 1.0;
        }

    }
    catch(exception const& exc)
    {
        throw exception_invalid_value(
            msg_invalid_function_spec(), &exc) << JAGLOC;
    }

    // decide which IIndirect implementation will be passed to
    // IndirectObjectFwd
    if (m_fn_type==TYPE_4)
    {
        m_stream->set_writer_callback(
            bind(&FunctionObj::on_write, this, _1));
        reset_indirect_object_worker(m_stream.get());
    }
    else
    {
        m_callback.reset(
            new IndirectObjectCallback(
                doc, bind(&FunctionObj::on_write, this, _1)));
        reset_indirect_object_worker(m_callback);
    }
}

//
//
//
void FunctionObj::on_before_output()
{
    // TYPE_3: get references to functions
    if (m_fn_type == TYPE_3)
    {
        m_function_refs.resize(m_functions.size());
        ResourceManagement* resmgm = &m_doc.res_mgm();
        std::transform(m_functions.begin(),
                       m_functions.end(),
                       m_function_refs.begin(),
                       bind(&ResourceManagement::function_ref, resmgm, _1));
    }
}

//
//
//
void FunctionObj::on_write(ObjFmt& fmt)
{
    // if type 4 then we are called as a part of a stream dictionary; in other
    // cases we need to start/end the dictionary here
    if (m_fn_type != TYPE_4)
        fmt.dict_start();

    fmt.dict_key("FunctionType").space().output(m_fn_type);
    output_array("Domain", fmt, m_domain.begin(), m_domain.end());
    output_array("Range", fmt, m_range.begin(), m_range.end());
    // TYPE_4 done
    if(m_fn_type == TYPE_2)
    {
        output_array("C0", fmt, m_c0.begin(), m_c0.end());
        output_array("C1", fmt, m_c1.begin(), m_c1.end());
        fmt.dict_key("N").space().output(m_interpolation_exponent);
    }
    else if (m_fn_type == TYPE_3)
    {
        fmt.dict_key("Functions");
        output_ref_array(fmt, m_function_refs.begin(), m_function_refs.end());
        output_array("Bounds", fmt, m_bounds.begin(), m_bounds.end());
        output_array("Encode", fmt, m_encode.begin(), m_encode.end());
    }

    if (m_fn_type != TYPE_4)
        fmt.dict_end();
}

// ---------------------------------------------------------------------------
//                           Resource management
//

namespace
{
  template<class Handle, class Map, class Table>
  IndirectObjectRef const& resource_ref(Handle handle, Map& map, Table& table)
  {
      typename Map::iterator it = map.find(handle);
      if (it == map.end())
      {
          IIndirectObject& resource(table.lookup(handle));
          resource.output_definition();
          it = map.insert(std::make_pair(handle,
                                         IndirectObjectRef(resource))).first;
      }
      return it->second;
  };
} // namespace

/// ctor
ResourceManagement::ResourceManagement(DocWriterImpl& doc)
    : m_doc(doc)
    , m_font_management(doc)
{
}

//
//
//
ResourceManagement::~ResourceManagement()
{
    // delete canvases
    CanvasMap::iterator it = m_canvas_map.begin();
    for(; it != m_canvas_map.end(); ++it)
        delete it->first;
}

//////////////////////////////////////////////////////////////////////////
IImageMan& ResourceManagement::image_man()
{
    return *m_doc.resource_ctx().image_man();
}

//////////////////////////////////////////////////////////////////////////
// COLOR SPACES
//////////////////////////////////////////////////////////////////////////

//
//
//
PatternHandle
ResourceManagement::tiling_pattern_load(Char const* pattern, ICanvas* canvas)
{
    CanvasRecord* canvas_rec = canvas_record(canvas);
    if (!canvas_rec || !canvas_rec->can_be_shared)
        throw exception_invalid_value(msg_invalid_argument()) << JAGLOC;

    std::auto_ptr<TilingPatternImpl> new_one(
        new TilingPatternImpl(m_doc, pattern, canvas));

    PatternHandle ph = m_pattern_table.add(new_one.release());

    // unset 'can_be_shared' flag so that the canvas cannot be used in other
    // objects
    canvas_rec->can_be_shared = false;

    return ph;
}

//
//
//
IIndirectObject& ResourceManagement::pattern(PatternHandle ph)
{
    return m_pattern_table.lookup(ph);
}

/// Adjusts a pattern matrix for the topdown mode.
///
/// Visits a pattern implementation, clones it and adds it to the
/// pattern table.
///
class ResourceManagement::PatternVisitorTopdown
    : public VisitorNoOp
{
    ResourceManagement& m_res_mgm;
    double m_page_height;
    PatternHandle m_handle;

public:
    PatternVisitorTopdown(ResourceManagement& res_mgm, double page_height)
        : m_res_mgm(res_mgm)
        , m_page_height(page_height)
    {
    }

    PatternHandle handle() const {
        JAG_PRECONDITION(is_valid(m_handle));
        return m_handle;
    }

public: // visitor methods
    //
    bool visit(TilingPatternImpl& visited)
    {
        // the pattern canvas cannot be shared since the pattern matrix is part
        // of the canvas' content stream definition
        CanvasImpl* canvas =
            checked_static_cast<CanvasImpl*>(m_res_mgm.canvas_create());

        CanvasImpl* visited_canvas =
            checked_static_cast<CanvasImpl*>(visited.canvas());

        visited_canvas->copy_to(*canvas);
        std::auto_ptr<TilingPatternImpl> pattern(
            new TilingPatternImpl(m_res_mgm.m_doc,
                                  visited.definition_string(),
                                  canvas));

        adjust_matrix(pattern.get(), visited);
        m_handle = m_res_mgm.m_pattern_table.add(pattern.release());
        return true;
    }

    //
    bool visit(ShadingPatternImpl& visited)
    {
        std::auto_ptr<ShadingPatternImpl> pattern(
            new ShadingPatternImpl(m_res_mgm.m_doc,
                                   visited.definition_string(),
                                   visited.shading_handle()));

        adjust_matrix(pattern.get(), visited);
        m_handle = m_res_mgm.m_pattern_table.add(pattern.release());
        return true;
    }

private:
    void adjust_matrix(PatternBase* pattern, PatternBase const& visited)
    {
        // adjust the pattern matrix
        if (visited.matrix().empty())
        {
            pattern->matrix(trans_affine_t(1, 0, 0, -1, 0, m_page_height));
        }
        else
        {
            JAG_ASSERT(visited.matrix().size() == 6);
            trans_affine_t mtx_orig(&visited.matrix()[0]);
            trans_affine_t mtx(1, 0, 0, -1, 0, m_page_height);
            mtx *= mtx_orig;
            pattern->matrix(mtx);
        }
    }
};

//
//
//
bool operator<(ResourceManagement::PatternAndPageHeight const&lhs,
               ResourceManagement::PatternAndPageHeight const&rhs)
{
    if (lhs.first > rhs.first)
        return false;

    if (lhs.second < lhs.second)
        return true;

    return false;
}

//
//
//
IndirectObjectRef const&
ResourceManagement::pattern_ref(PatternHandle ph, double page_height)
{
    if (page_height == 0.0)
        return resource_ref(ph, m_patterns, m_pattern_table);

    // In the topdown mode, the pattern's matrix must be
    // adjusted. m_patterns_by_page_height maintains {(orig_pattern,
    // page_height): adjusted_pattern} dictionary.
    typedef PatternsByPageHeight::iterator It;
    const PatternAndPageHeight key(ph, page_height);
    It found = m_patterns_by_page_height.find(key);
    if (found == m_patterns_by_page_height.end())
    {
        PatternVisitorTopdown visitor(*this, page_height);
        pattern(ph).accept(visitor);
        found = m_patterns_by_page_height.insert(
            PatternsByPageHeight::value_type(key,
                                             visitor.handle())).first;
    }

    return resource_ref(found->second, m_patterns, m_pattern_table);
}

//
//
//
IndirectObjectRef const& ResourceManagement::shading_ref(ShadingHandle sh)
{
    return resource_ref(sh, m_shadings, m_shading_table);
}

//
//
//
PatternHandle
ResourceManagement::shading_pattern_load(Char const* pattern,
                                         ColorSpaceHandle cs,
                                         FunctionHandle const* funcs,
                                         UInt num_functions)
{
    // the spec string is parsed twice; it would be possible to share
    // ParsedResult instance created in ShadingImpl but that would introduce
    // dependencies on spirit
    ShadingHandle shading_handle = m_shading_table.add(
        new ShadingImpl(m_doc, pattern, cs, funcs, num_functions));

    PatternHandle pattern_handle = m_pattern_table.add(
        new ShadingPatternImpl(m_doc, pattern, shading_handle));

    m_pattern_to_shading.insert(std::make_pair(pattern_handle, shading_handle));
    return pattern_handle;
}

//
//
//
ShadingHandle
ResourceManagement::shading_from_pattern(PatternHandle handle)
{
    PatternToShadingMap::iterator it = m_pattern_to_shading.find(handle);
    if (it == m_pattern_to_shading.end())
        throw exception_invalid_value(msg_invalid_argument()) << JAGLOC;

    return it->second;
}

/**
 * @brief Retrives color space reference.
 *
 * @param handle color space
 * @return Reference to the color space.
 *
 * Note, that ColorSpaceHandle can represent either a color space
 * residing in the ColorSpace Manager or a trivial namespace (e.g.
 * DEVICE_RGB) that does not have any record in CS Manager. The latter
 * color space handles should not be passed to this method.
 **/
IndirectObjectRef const&
ResourceManagement::color_space_ref(ColorSpaceHandle handle)
{
    return reference_provider<ColorSpaceObj>(
        handle
        , m_color_spaces
        , identity<ColorSpaceHandle>()
        , m_doc);
}

//////////////////////////////////////////////////////////////////////////
// IMAGES
//////////////////////////////////////////////////////////////////////////

/**
 * @brief retrieves indirect object containing given image
 *
 * @param image_id image
 *
 * image is outputted during the first call requiring indirect object
 * of that image
 */
IndirectObjectRef const& ResourceManagement::image_reference(ImageHandle image_id)
{
    return reference_provider<ImageXObject>(
          image_id
        , m_images
        , bind(&IImageMan::image_data, &image_man(), _1)
        , m_doc
   );
}

//////////////////////////////////////////////////////////////////////////
// Functions
//////////////////////////////////////////////////////////////////////////

IndirectObjectRef const& ResourceManagement::function_ref(FunctionHandle handle)
{
    FunctionsMap::iterator it = m_functions.find(handle);
    if (it == m_functions.end())
    {
        IIndirectObject& fn(m_fun_table.lookup(handle));
        fn.output_definition();
        it = m_functions.insert(
            std::make_pair(handle, IndirectObjectRef(fn))).first;
    }
    return it->second;
}

//
//
//
FunctionHandle ResourceManagement::function_2_load(Char const* fun)
{
    return m_fun_table.add(new FunctionObj(m_doc, fun, FunctionObj::TYPE_2));
}

//
//
//
FunctionHandle ResourceManagement::function_4_load(Char const* fun)
{
    return m_fun_table.add(new FunctionObj(m_doc, fun, FunctionObj::TYPE_4));
}

FunctionHandle ResourceManagement::function_3_load(Char const* fun,
                               FunctionHandle const* funs, UInt nr_funs)
{
    return m_fun_table.add(new FunctionObj(m_doc, fun,
                                           FunctionObj::TYPE_3, funs, nr_funs));
}

//////////////////////////////////////////////////////////////////////////
// IMAGE MASKS
//////////////////////////////////////////////////////////////////////////

/**
 * @brief retrieves indirect object containing given image mask
 *
 * @param imagemask image mask
 *
 * image mask is outputted during the first call requiring indirect object
 * of that image mask
 */
IndirectObjectRef const&  ResourceManagement::image_mask_reference(ImageMaskHandle imagemask)
{
    return reference_provider<ImageXObjectMask>(
          imagemask
        , m_image_masks
        , bind(&IImageMan::image_mask_data, &image_man(), _1)
        , m_doc
   );
}

//////////////////////////////////////////////////////////////////////////
GraphicsStateHandle ResourceManagement::register_graphics_state(GraphicsStateDictionary const& gs_dict)
{
    GraphicsStateToHandle::iterator it = m_gs_to_handle.find(gs_dict);
    if (it == m_gs_to_handle.end())
    {
        GraphicsStateHandle result(m_handle_to_gs.register_resource(gs_dict));
        m_gs_to_handle.insert(GraphicsStateToHandle::value_type(gs_dict, result));
        return result;
    }

    return it->second;
}

/**
 * @brief retrieves indirect object containing given graphics state
 *
 * @param gs_handle graphics state handle
 *
 * graphics state is outputted during the first call requiring indirect object
 * of that graphics state
 */
IndirectObjectRef ResourceManagement::graphics_state_reference(GraphicsStateHandle gs_handle)
{
    typedef GSHandleToGSDict::record_t const& (GSHandleToGSDict::*overload_t)(GSHandleToGSDict::handle_t) const;

    return reference_provider<GraphicsStateDictionaryObject>(
        gs_handle
        , m_gs_to_obj
        , bind(static_cast<overload_t>(&GSHandleToGSDict::resource_record), &m_handle_to_gs, _1)
        , m_doc
   );
}

/// outputs queued resources
void ResourceManagement::finalize()
{
    m_font_management.output_fonts();
}

//
//
//
ICanvas* ResourceManagement::canvas_create() const
{
    std::auto_ptr<CanvasImpl> canvas(m_doc.create_canvas_impl());
    CanvasImpl* canvas_raw = canvas.get();
    m_canvas_map.insert(
        CanvasMap::value_type(
            static_cast<ICanvas*>(canvas.release()),
            CanvasRecord()));

    return canvas_raw;
}

//
// Gives reference to a shared canvas
//
IndirectObjectRef& ResourceManagement::canvas_ref(ICanvas* canvas)
{
    CanvasRecord* canvas_rec = canvas_record(canvas);
    JAG_PRECONDITION(
        // known canvas
        canvas_rec &&
        // cannot be private
        canvas_rec->can_be_shared);

    if (!is_valid(canvas_rec->ref))
    {
        CanvasImpl* canvas_impl = checked_static_cast<CanvasImpl*>(canvas);
        canvas_impl->output_definition();
        canvas_rec->ref.reset(*canvas_impl);
    }

    JAG_ASSERT(is_valid(canvas_rec->ref));
    return canvas_rec->ref;
}

//
//
//
ResourceManagement::CanvasRecord*
ResourceManagement::canvas_record(ICanvas* canvas)
{
    CanvasMap::iterator it = m_canvas_map.find(canvas);
    return it != m_canvas_map.end()
        ? &it->second
        : 0;
}

}} //namespace jag::pdf

max_stars_repo_name: jgresula/jagpdf

max_issues_repo_name: jgresula/jagpdf

max_forks_repo_name: jgresula/jagpdf


text:
#include <iostream>
#include <Eigen/Sparse>
#include <unsupported/Eigen/SparseExtra>
#include <igl/readMSH.h>

void circumcenter(const Eigen::Vector3d& a, const Eigen::Vector3d& b, const Eigen::Vector3d& c, Eigen::Vector3d& cc)
{
    const double l[3]{
        (b - c).squaredNorm(),
        (a - c).squaredNorm(),
        (a - b).squaredNorm()
    };

    const double ba[3]{l[0] * (l[1] + l[2] - l[0]), l[1] * (l[2] + l[0] - l[1]), l[2] * (l[0] + l[1] - l[2])};
    const double sum = ba[0] + ba[1] + ba[2];

    cc = (ba[0] / sum) * a + (ba[1] / sum) * b + (ba[2] / sum) * c;
}

void circumcenter(const Eigen::Matrix<double, 4, 3>& t, Eigen::Vector3d& c)
{
    Eigen::Matrix3d A;
    Eigen::Vector3d b;

    const double n0 = t.row(0).squaredNorm();

    for(int k = 0; k < 3; ++k)
    {
        A.row(k) = t.row(k + 1) - t.row(0);
        b(k) = t.row(k + 1).squaredNorm() - n0;
    }

    c = 0.5 * A.fullPivHouseholderQr().solve(b);
}

double volume(const Eigen::Vector3d& a, const Eigen::Vector3d& b, const Eigen::Vector3d& c, const Eigen::Vector3d& d)
{
    Eigen::Matrix3d A;
    A.col(0) = b - a;
    A.col(1) = c - a;
    A.col(2) = d - a;

    return A.determinant() / 6.;
}

void dualLaplace(const Eigen::MatrixXd& V, const Eigen::MatrixXi& T, Eigen::SparseMatrix<double>& L, Eigen::SparseMatrix<double>& M)
{
    const size_t nt = T.rows();
    const size_t nv = V.rows();

    const int turn[4][4]
    {
        {-1, 2, 3, 1},
        {3, -1, 0, 2},
        {1, 3, -1, 0},
        {2, 0, 1, -1}
    };

    auto getTet = [&](const int i, Eigen::Matrix<double, 4, 3>& t)
    {
        for(int k = 0; k < 4; ++k)
        {
            t.row(k) = V.row(T(i, k));
        }
    };

    std::vector<Eigen::Triplet<double>> tripL, tripM;

    Eigen::Vector3d cc;
    Eigen::Matrix<double, 4, 3> t;

    for(int k = 0; k < nt; ++k)
    {
        getTet(k, t);
        circumcenter(t, cc);

        for(int i = 0; i < 4; ++i)
        {
            for(int j = 0; j < 4; ++j)
            {
                if(i != j)
                {
                    Eigen::Vector3d cf;
                    circumcenter(t.row(i), t.row(j), t.row(turn[i][j]), cf);

                    const Eigen::Vector3d ce = 0.5 * (t.row(i) + t.row(j));

                    const double vol = volume(t.row(i), ce, cf, cc);
                    const double wij = 6. * vol / (t.row(i) - t.row(j)).squaredNorm();

                    tripL.emplace_back(T(k, i), T(k, j), wij);
                    tripL.emplace_back(T(k, j), T(k, i), wij);

                    tripL.emplace_back(T(k, i), T(k, i), -wij);
                    tripL.emplace_back(T(k, j), T(k, j), -wij);

                    tripM.emplace_back(T(k, i), T(k, i), vol);
                    tripM.emplace_back(T(k, j), T(k, j), vol);
                }
            }
        }
    }

    L.resize(nv, nv);
    M.resize(nv, nv);

    L.setFromTriplets(tripL.begin(), tripL.end());
    M.setFromTriplets(tripM.begin(), tripM.end());
}

int main(int argc, const char * argv[])
{
    if(argc == 2)
    {
        Eigen::SparseMatrix<double> L, M;
        Eigen::MatrixXd V;
        Eigen::MatrixXi T;

        if(igl::readMSH(argv[1], V, T))
        {
            dualLaplace(V, T, L, M);
            Eigen::saveMarket(L, "L.mtx");
            Eigen::saveMarket(M, "M.mtx");
        }
    }

    return 0;
}

max_stars_repo_name: PhHerholz/DualTetLaplace

max_issues_repo_name: PhHerholz/DualTetLaplace

max_forks_repo_name: PhHerholz/DualTetLaplace


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

#include <fstream>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include "vm.h"
#include "vm_control.h"
#include "helpers.h"

namespace {
	std::string dump_regs( virtual_machine_t & vm ) {
		std::stringstream ss;
		for( size_t n = 0; n < vm.registers.size( ); ++n ) {
			ss << "REG" << n << ": " << vm.registers[n] << "\n";
		}
		ss << "Instruction ptr: " << vm.instruction_ptr << "\n";
		return ss.str( );
	}

}

namespace {
	void save_to_text_file( boost::string_ref fname, boost::string_ref text ) {
		std::ofstream fout;
		fout.open( fname.data( ) );
		if( !fout ) {
			std::cerr << "Error saving to " << fname << "\n";
			exit( EXIT_FAILURE );
		}
		fout << text;
		fout.close( );
	}

}

void vm_control::show_asm( virtual_machine_t& vm, std::vector<uint16_t> const& tokens ) {
	uint16_t from_address = 0;
	uint16_t to_address = std::numeric_limits<uint16_t>::max( );
	if( tokens.size( ) > 0 ) {
		from_address = tokens[0];
	}
	if( tokens.size( ) > 1 ) {
		to_address = tokens[1];
	}

	full_dump( vm, from_address, to_address );
	std::cout << "\n\n";
}

void vm_control::save_asm( virtual_machine_t & vm, boost::string_ref fname ) {
	save_to_text_file( fname, full_dump_string( vm ) );
	std::cout << "Saved file to " << fname << "\n";
}

void vm_control::get_ip( virtual_machine_t & vm ) {
	std::cout << "Current instruction ptr is " << vm.instruction_ptr << "\n";
}

void vm_control::tick( virtual_machine_t & vm ) {
	vm.tick( true );
	get_ip( vm );
}

void vm_control::get_regs( virtual_machine_t & vm ) {
	std::cout << "Current register values\n";
	std::cout << dump_regs( vm ) << "\n";
}

void vm_control::get_bps( virtual_machine_t & vm ) {
	std::cout << "Current breakpoints(" << vm.debugging.breakpoints.size( ) << ")\n";
	for( auto const & bp : vm.debugging.breakpoints ) {
		std::cout << bp << "\n";
	}
}

void vm_control::clear_bps( virtual_machine_t & vm ) {
	std::cout << "Clearing " << vm.debugging.breakpoints.size( ) << " breakpoints\n";
	vm.debugging.breakpoints.clear( );
}

void vm_control::get_memory_traps(virtual_machine_t& vm) {
	std::cout << "Current memory traps(" << vm.debugging.memory_traps.size( ) << ")\n";
	for( auto const & bp : vm.debugging.memory_traps ) {
		std::cout << bp << "\n";
	}
}

void vm_control::clear_memory_traps( virtual_machine_t& vm ) {
	std::cout << "Clearing " << vm.debugging.memory_traps.size( ) << " memory traps\n";
	vm.debugging.memory_traps.clear( );
}

void vm_control::save_state( virtual_machine_t & vm, boost::string_ref fname ) {
	vm.save_state( fname );
	std::cout << "State saved to file '" << fname << "'\n";
}

void vm_control::load_state( virtual_machine_t & vm, boost::string_ref fname ) {
	vm.load_state( fname );
	std::cout << "Loaded state from file '" << fname << "'\n";
}

void vm_control::show_argument_stack( virtual_machine_t & vm ) {
	std::cout << "Current argument stack(" << vm.argument_stack.size( ) << ")\n";
	for( size_t n = 0; n < vm.argument_stack.size( ); ++n ) {
		std::cout << n << ": " << vm.argument_stack[n] << "\n";
	}
}

void vm_control::show_program_stack( virtual_machine_t & vm ) {
	std::cout << "Current program stack(" << vm.program_stack.size( ) << ")\n";
	for( size_t n = 0; n < vm.program_stack.size( ); ++n ) {
		std::cout << n << ": " << vm.program_stack[n] << "\n";
	}
}

void vm_control::save_trace(virtual_machine_t& vm, boost::string_ref fname) {
	save_to_text_file( fname, vm.debugging.trace.to_json( ) );
	boost::filesystem::rename( "trace_state.bin", fname.to_string( ) + ".state" );
}

void vm_control::start_tracing( virtual_machine_t & vm ) {
	save_state( vm, "trace_state.bin" );
	vm.debugging.enable_tracing = true;
}

void vm_control::stop_tracing( virtual_machine_t & vm ) {
	vm.debugging.enable_tracing = false;
}


text:
#include <unistd.h>
#include <signal.h>

#include <cmath>

#include <memory>
#include <vector>
#include <string>
#include <utility>

#include <boost/program_options.hpp>

#include "glog/logging.h"

#include "executor_thread.h"
#include "helpers.h"
#include "redis_phi_matrix.h"
#include "redis_client.h"
#include "protocol.h"
#include "token.h"

namespace po = boost::program_options;

// ToDo(MelLain): add correct signal handling and threads termination

//volatile sig_atomic_t signal_flag = 0;

//void signal_handler(int sig) {
//  signal_flag = 1;
//}

struct Parameters {
  int num_topics;
  int num_inner_iters;
  int num_threads;
  std::string batches_dir_path;
  std::string vocab_path;
  std::string redis_ip;
  std::string redis_port;
  int continue_fitting;
  std::string caching_mode;
  int delayed_update;
  int token_begin_index;
  int token_end_index;
  int batch_begin_index;
  int batch_end_index;
  int executor_id;
};

void log_parameters(const Parameters& parameters) {
    LOG(INFO) << "num-topics: "        << parameters.num_topics        << "; "
              << "num-inner-iter: "    << parameters.num_inner_iters   << "; "
              << "num-threads: "       << parameters.num_threads       << "; "
              << "batches-dir-path: "  << parameters.batches_dir_path  << "; "
              << "vocab-path: "        << parameters.vocab_path        << "; "
              << "redis-ip: "          << parameters.redis_ip          << "; "
              << "redis-port: "        << parameters.redis_port        << "; "
              << "continue-fitting: "  << parameters.continue_fitting  << "; "
              << "caching-mode: "      << parameters.caching_mode      << "; "
              << "delayed-update: "    << parameters.delayed_update    << "; "
              << "token-begin-index: " << parameters.token_begin_index << "; "
              << "token-end-index: "   << parameters.token_end_index   << "; "
              << "batch-begin-index: " << parameters.batch_begin_index << "; "
              << "batch-end-index: "   << parameters.batch_end_index   << "; "
              << "executor-id: "       << parameters.executor_id;
}

void check_parameters(const Parameters& parameters) {
  if (parameters.num_topics <= 0) {
    throw std::runtime_error("num_topics should be a positive integer");
  }

  if (parameters.num_inner_iters <= 0) {
    throw std::runtime_error("num_inner_iters should be a positive integer");
  }

  if (parameters.num_threads <= 0) {
    throw std::runtime_error("num_threads should be a positive integer");
  }

  if (parameters.batches_dir_path == "") {
    throw std::runtime_error("batches_dir_path should be non-empty");
  }

  if (parameters.vocab_path == "") {
    throw std::runtime_error("vocab_path should be non-empty");
  }

  if (parameters.redis_ip == "") {
    throw std::runtime_error("redis_ip should be non-empty");
  }

  if (parameters.redis_port == "") {
    throw std::runtime_error("redis_port should be non-empty");
  }

  if (parameters.continue_fitting != 0 && parameters.continue_fitting != 1) {
    throw std::runtime_error("continue_fitting should be equal to 0 or 1");
  }

  if (parameters.caching_mode != CACHING_MODE_NONE &&
      parameters.caching_mode != CACHING_MODE_PWT &&
      parameters.caching_mode != CACHING_MODE_NWT &&
      parameters.caching_mode != CACHING_MODE_ALL)
  {
    throw std::runtime_error("caching_mode should be in none|pwt|nwt|all");
  }

  if (parameters.delayed_update != 0 && parameters.delayed_update != 1) {
    throw std::runtime_error("delayed_update should be equal to 0 or 1");
  }

  if (parameters.redis_port == "") {
    throw std::runtime_error("redis_port should be non-empty");
  }

  if (parameters.token_begin_index < 0 || parameters.token_end_index < 0
      || parameters.token_end_index < parameters.token_begin_index)
  {
    throw std::runtime_error("token_begin_index should be > 0 and <= token_end_index");
  }

  if (parameters.batch_begin_index < 0 || parameters.batch_end_index < 0
      || parameters.batch_end_index < parameters.batch_begin_index)
  {
    throw std::runtime_error("batch_begin_index should be > 0 and <= batch_end_index");
  }

  if (parameters.executor_id < 0) {
    throw std::runtime_error("executor_id should be a non-negative integer");
  }
}

bool parse_and_print_parameters(int argc, char* argv[], Parameters* parameters) {
  po::options_description all_options("Options");
  all_options.add_options()
    ("help", "Show help")
    ("num-topics",        po::value(&parameters->num_topics)->default_value(1),            "Number of topics")                                // NOLINT
    ("num-inner-iter",    po::value(&parameters->num_inner_iters)->default_value(1),       "Number of document passes")                       // NOLINT
    ("num-threads",       po::value(&parameters->num_threads)->default_value(1),           "Number of executor processor threads")            // NOLINT
    ("batches-dir-path",  po::value(&parameters->batches_dir_path)->default_value("."),    "Path to files with documents")                    // NOLINT
    ("vocab-path",        po::value(&parameters->vocab_path)->default_value("."),          "Path to files with documents")                    // NOLINT
    ("redis-ip",          po::value(&parameters->redis_ip)->default_value(""),             "IP of redis instance")                            // NOLINT
    ("redis-port",        po::value(&parameters->redis_port)->default_value(""),           "Port of redis instance")                          // NOLINT
    ("continue-fitting",  po::value(&parameters->continue_fitting)->default_value(0),      "1 - continue fitting redis model, 0 - restart")   // NOLINT
    ("caching-mode",      po::value(&parameters->caching_mode)->default_value("none"),     "Cache usage policy: none|pwt|nwt|all")            // NOLINT
    ("delayed-update",    po::value(&parameters->delayed_update)->default_value(0),        "1 - update n_wt matrix per iter, 0 - per batch")  // NOLINT
    ("token-begin-index", po::value(&parameters->token_begin_index)->default_value(0),     "Index of token to init/norm from")                // NOLINT
    ("token-end-index",   po::value(&parameters->token_end_index)->default_value(0),       "Index of token to init/norm to (excluding)")      // NOLINT
    ("batch-begin-index", po::value(&parameters->batch_begin_index)->default_value(0),     "Index of batch to process from")                  // NOLINT
    ("batch-end-index",   po::value(&parameters->batch_end_index)->default_value(0),       "Index of batch to process to (excluding)")        // NOLINT
    ("executor-id",       po::value(&parameters->executor_id)->default_value(-1),          "Unique identifier of the process")                // NOLINT
    ;

  po::variables_map variables_map;
  store(po::command_line_parser(argc, argv).options(all_options).run(), variables_map);
  notify(variables_map);

  bool show_help = (variables_map.count("help") > 0);
  if (show_help) {
    std::cerr << all_options;
    return true;
  }

  return false;
}

std::vector<std::pair<int, int>> get_indices(int num_threads, int begin_index, int end_index) {
  int step = std::ceil((end_index - begin_index) / static_cast<double>(num_threads));

  std::vector<std::pair<int, int>> retval;
  for (int thread_id = 0; thread_id < num_threads; ++thread_id) {
    retval.push_back(std::make_pair(begin_index + step * thread_id,
                                    std::min(begin_index + step * (thread_id + 1), end_index)));
  }

  return retval;
}

int main(int argc, char* argv[]) {
  //signal(SIGINT, signal_handler);

  Parameters parameters;
  bool is_help_call = parse_and_print_parameters(argc, argv, &parameters);
  if (is_help_call) {
    return 0;
  }

  FLAGS_minloglevel = 0;
  FLAGS_log_dir = ".";

  const int executor_id = parameters.executor_id;
  std::string log_file = std::string("cluster-bigartm-") + std::to_string(executor_id);
  google::InitGoogleLogging(log_file.c_str());
  log_parameters(parameters);
  check_parameters(parameters);

  LOG(INFO) << "Executor " << executor_id << ": has started";

  LOG(INFO) << "Executor " << executor_id << ": start connecting redis at "
            << parameters.redis_ip << ":" << parameters.redis_port;

  auto redis_client = std::shared_ptr<RedisClient>(new RedisClient(parameters.redis_ip,
                                                                   std::stoi(parameters.redis_port)));

  LOG(INFO) << "Executor " << executor_id << ": finish connecting to redis";

  LOG(INFO) << "Executor " << executor_id << ": start creating threads";

  std::vector<std::string> command_keys = generate_command_keys(parameters.executor_id, parameters.num_threads);
  std::vector<std::string> data_keys = generate_data_keys(parameters.executor_id, parameters.num_threads);

  try {
    std::vector<std::pair<int, int>> token_indices = get_indices(parameters.num_threads,
                                                                 parameters.token_begin_index,
                                                                 parameters.token_end_index);

    std::vector<std::pair<int, int>> batch_indices = get_indices(parameters.num_threads,
                                                                 parameters.batch_begin_index,
                                                                 parameters.batch_end_index);
    LOG(INFO) << "Executor " << executor_id
              << ": first token index is " << token_indices[0].first
              << ", last token index is " << token_indices[token_indices.size() - 1].second
              << "; first batch index is " << batch_indices[0].first
              << ", last batch index is " << batch_indices[batch_indices.size() - 1].second;

    std::vector<std::string> topics;
    for (int i = 0; i < parameters.num_topics; ++i) {
      topics.push_back("topic_" + std::to_string(i));
    }

    LOG(INFO) << "Executor " << executor_id << ": start creating matrices";

    PhiMatrixCacheMode pwt_mode = PhiMatrixCacheMode::NONE;
    PhiMatrixCacheMode nwt_mode = PhiMatrixCacheMode::NONE;

    if (parameters.caching_mode == CACHING_MODE_PWT) {
      pwt_mode = PhiMatrixCacheMode::READ;
    } else if (parameters.caching_mode == CACHING_MODE_NWT) {
      nwt_mode = PhiMatrixCacheMode::WRITE;
    } else if (parameters.caching_mode == CACHING_MODE_ALL) {
      pwt_mode = PhiMatrixCacheMode::READ;
      nwt_mode = PhiMatrixCacheMode::WRITE;
    }

    auto p_wt = std::shared_ptr<RedisPhiMatrix>(new RedisPhiMatrix(ModelName("pwt"), topics, pwt_mode));
    auto n_wt = std::shared_ptr<RedisPhiMatrix>(new RedisPhiMatrix(ModelName("nwt"), topics, nwt_mode));

    int counter = 0;
    auto zero_vector = std::vector<float>(p_wt->topic_size(), 0.0f);

    std::ifstream fin;
    std::string line;
    fin.open(parameters.vocab_path);

    bool continue_fitting = parameters.continue_fitting == 1;
    while (std::getline(fin, line)) {
      auto token = Token(DefaultClass, line);
      bool add_token_to_redis = false;

      if (counter >= parameters.token_begin_index && counter < parameters.token_end_index) {
        add_token_to_redis = !continue_fitting;
      }

      p_wt->add_token(redis_client, token, add_token_to_redis, zero_vector);
      n_wt->add_token(redis_client,
                      token,
                      add_token_to_redis,
                      add_token_to_redis ? Helpers::generate_random_vector(p_wt->topic_size(), token) : zero_vector);
      ++counter;
    }
    fin.close();

    LOG(INFO) << "Executor " << executor_id << ": " << "number of tokens: " << p_wt->token_size()
              << "; redis matrices had been reset: " << !continue_fitting;

    std::vector<std::shared_ptr<ExecutorThread>> threads;
    for (int thread_id = 0; thread_id < parameters.num_threads; ++thread_id) {
      std::string ip = parameters.redis_ip;
      int port = std::stoi(parameters.redis_port);
      auto thread_client = std::shared_ptr<RedisClient>(new RedisClient(ip, port));
      auto p_wt_client = std::shared_ptr<RedisClient>(new RedisClient(ip, port));
      auto n_wt_client = std::shared_ptr<RedisClient>(new RedisClient(ip, port));

      threads.push_back(std::shared_ptr<ExecutorThread>(
        new ExecutorThread(command_keys[thread_id],
                           data_keys[thread_id],
                           thread_client,
                           continue_fitting,
                           parameters.batches_dir_path,
                           token_indices[thread_id].first,
                           token_indices[thread_id].second,
                           batch_indices[thread_id].first,
                           batch_indices[thread_id].second,
                           parameters.num_inner_iters,
                           std::make_shared<RedisPhiMatrixAdapter>(RedisPhiMatrixAdapter(p_wt, p_wt_client)),
                           std::make_shared<RedisPhiMatrixAdapter>(RedisPhiMatrixAdapter(n_wt, n_wt_client)))
      ));
    }

    while (true) {
      bool terminate = false;
      for (const auto& thread : threads) {
        if (thread->is_stopping()) {
          terminate = true;
          break;
        }
      }

      if (terminate) {
        break;
      }
      usleep(2000);
    }
  } catch (const std::exception& error) {
    LOG(FATAL) << "Error in executor " << executor_id << ": " << error.what();
  } catch (...) {
    LOG(FATAL) << "Unknown error in executor " << executor_id;
  }

  return 0;
}

ext: cc

max_stars_repo_name: MelLain/cluster-bigartm

max_issues_repo_name: MelLain/cluster-bigartm

max_forks_repo_name: MelLain/cluster-bigartm


text:
/*
 *  compression_tree.cpp
 *
 *  Created on: 17-09-2015
 *      Author: Karol Dzitkowski
 */

#include "tree/compression_tree.hpp"
#include "compression/encoding_metadata_header.hpp"
#include "compression/default_encoding_factory.hpp"
#include "util/copy/cuda_array_copy.hpp"

#include <boost/make_shared.hpp>
#include <boost/bind.hpp>
#include <queue>

namespace ddj {

CompressionTree::CompressionTree() : _nextNo(0), _maxHeight(5){}

CompressionTree::CompressionTree(SharedCompressionStatisticsPtr stats)
	: _nextNo(0), _maxHeight(5), _stats(stats)
{}
CompressionTree::CompressionTree(SharedCompressionStatisticsPtr stats, int maxHeight)
	: _nextNo(0), _maxHeight(maxHeight), _stats(stats)
{}

CompressionTree::~CompressionTree(){}
CompressionTree::CompressionTree(const CompressionTree& other)
	: _nextNo(other._nextNo),
	  _root(other._root),
	  _maxHeight(other._maxHeight),
	  _stats(other._stats)
{}

CompressionTree::CompressionTree(EncodingType et, DataType dt)
	: _nextNo(0), _maxHeight(5)
{
	this->AddNode(CompressionNode::make_shared(et, dt), 0);
}

void CompressionTree::Reset()
{
	_nextNo = 0;
	_root = nullptr;
}

uint CompressionTree::GetNextNo()
{
	return _nextNo++;
}

SharedCompressionNodePtr CompressionTree::FindNode(uint nodeNo)
{
	if(nodeNo == 0) return _root;
	else return _root->FindChild(nodeNo);
}

bool CompressionTree::AddNode(SharedCompressionNodePtr node, uint parentNo)
{
	auto getNextNoFunc = boost::bind(&CompressionTree::GetNextNo, this);

	if(_root == nullptr) // we should add root
	{
		node->SetNo(getNextNoFunc);
		_root = node;
		return true;
	} else {
		auto parent = FindNode(parentNo);
		if(parent != nullptr)
		{
			node->SetNo(getNextNoFunc);
			node->SetParentNo(parentNo);
			parent->AddChild(node);
			return true;
		}
	}
	return false;
}

bool CompressionTree::RemoveNode(uint no)
{
	if(_root != nullptr)
	{
		if(no == 0)
		{
			_root = SharedCompressionNodePtr();
		} else {
			auto node = _root->FindChild(no);
			auto parent = _root->FindChild(node->GetParentNo());
			parent->RemoveChild(no);
		}
	}

	return false;
}

SharedCudaPtr<char> CompressionTree::Compress(SharedCudaPtr<char> data)
{
    auto compressionResults = _root->Compress(data);
    if(_stats != nullptr) this->UpdateStatistics(_stats);
    return CudaArrayCopy().Concatenate(compressionResults);
}

SharedCompressionNodePtr DecompressNodes(SharedCudaPtr<char> compressed_data, size_t& offset)
{
	// READ METADATA HEADER
	EncodingMetadataHeader header;
	size_t metadataHeaderSize = sizeof(EncodingMetadataHeader);
	CUDA_CALL( cudaMemcpy(&header, compressed_data->get()+offset, metadataHeaderSize, CPY_DTH) );
	offset += sizeof(EncodingMetadataHeader);

	// CREATE NODE
	EncodingType encType = (EncodingType)header.EncodingType;
	auto defaultEncodingFactory = DefaultEncodingFactory::Get(encType, (DataType)header.DataType);
	SharedCompressionNodePtr node(new CompressionNode(defaultEncodingFactory));

	// READ METADATA AND UPDATE OFFSET + SAVE TO NODE
	auto metadata = CudaPtr<char>::make_shared();
	metadata->fill(compressed_data->get()+offset, header.MetadataLength);
	offset += header.MetadataLength;
	node->SetMetadata(metadata);

	if(encType == EncodingType::none) // IF LEAF
	{
		// READ DATA AND UPDATE OFFSET
		size_t data_size;
		CUDA_CALL( cudaMemcpy(&data_size, metadata->get(), sizeof(size_t), CPY_DTH) );
		auto data = CudaPtr<char>::make_shared();
		data->fill(compressed_data->get()+offset, data_size);
		offset += data_size;
		node->SetData(data);
	}
	else //	RUN RECURSIVELY TO CHILD NODES
	{
		auto encoding = defaultEncodingFactory->Get();
		int noChildren = encoding->GetNumberOfResults();
		for(int i = 0; i < noChildren; i++)
		{
			auto childNode = DecompressNodes(compressed_data, offset);
			node->AddChild(childNode);
		}
	}

	return node;
}

SharedCudaPtr<char> CompressionTree::Decompress(SharedCudaPtr<char> data)
{
	Reset();
	size_t offset = 0;
	auto root = DecompressNodes(data, offset);
	AddNode(root, 0);
	return _root->Decompress();
}

size_t CompressionTree::GetPredictedSizeAfterCompression(SharedCudaPtr<char> data, DataType type)
{
	return _root->PredictCompressionSize(data, type);
}

void CompressionTree::Print(size_t performance)
{
	this->_root->Print();
	if(performance != 0) std::cout << "  -  " << performance;
	std::cout << std::endl;
}

std::string CompressionTree::ToString()
{
	return this->_root->ToString();
}

std::vector<CompressionTree> CompressionTree::CrossTree(std::vector<CompressionTree> subtrees)
{
	std::vector<CompressionTree> result;
	for(auto& subtree : subtrees)
	{
		auto treeCopy = *this;
		treeCopy.AddNode(subtree.FindNode(0), 0);
		result.push_back(treeCopy);
	}
	return result;
}

CompressionTree CompressionTree::Copy()
{
	CompressionTree tree;
	tree._nextNo = this->_nextNo;
	tree._root = this->_root->Copy();
	return tree;
}

void CompressionTree::Fix()
{
	this->_root->Fix();
}

CompressionEdgeVector CompressionTree::GetEdges()
{
	CompressionEdgeVector result;
	int max = (1 << (_maxHeight+1)) - 2, no = 0;
	std::queue<SharedCompressionNodePtr> fifo;
	fifo.push(this->_root);
	auto fake = CompressionNode::make_shared(EncodingType::none, DataType::d_int);

	while(!fifo.empty() && no < max)
	{
		auto el = fifo.front(); fifo.pop();
		auto chld = el->Children();

		// LEFT
		if(chld.size() >= 1) {
			result.push_back(CompressionEdge(el, chld[0], no));
			fifo.push(chld[0]);
		} else {
			fifo.push(fake);
		} no++;

		// RIGHT
		if(chld.size() >= 2) {
			result.push_back(CompressionEdge(el, chld[1], no));
			fifo.push(chld[1]);
		} else {
			fifo.push(fake);
		} no++;
	}

	return result;
}

void CompressionTree::UpdateStatistics(SharedCompressionStatisticsPtr stats)
{
	auto edges = GetEdges();
	for(auto& edge : edges)
	{
		double ratio = (edge.From()->GetCompressionRatio() + edge.To()->GetCompressionRatio()) / 2.0;
		stats->Update(edge.GetNo(), edge.GetType(), ratio);
	}
}

} /* namespace ddj */

max_stars_repo_licenses: MIT Unlicense

max_issues_repo_licenses: MIT Unlicense

max_forks_repo_licenses: MIT Unlicense


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

#ifndef PF_LOCALIZATION__PARTICLE_FILTER_HPP_
#define PF_LOCALIZATION__PARTICLE_FILTER_HPP_

// headers in this package
#include <pf_localization/twist_estimator.hpp>

// headers in ROS
#include <geometry_msgs/msg/twist_stamped.hpp>
#include <geometry_msgs/msg/point_stamped.hpp>
#include <geometry_msgs/msg/pose_stamped.h>
#include <geometry_msgs_data_buffer/pose_stamped_data_buffer.hpp>
#include <geometry_msgs_data_buffer/twist_stamped_data_buffer.hpp>
#include <quaternion_operation/quaternion_operation.h>

// headers in Boost
#include <boost/optional.hpp>

// headers in STL
#include <float.h>
#include <map>
#include <random>
#include <memory>
#include <string>
#include <vector>

namespace pf_localization
{
struct Particle
{
  geometry_msgs::msg::PoseStamped pose;
  double weight;
};

class ParticleFilter
{
public:
  ParticleFilter(
    int num_particles, double buffer_length, bool estimate_3d_pose,
    double expansion_reset_ess_threashold, double max_expansion_orientation,
    double max_expantion_position,
    double sensor_reset_ess_threashold, double max_sensor_reset_orientation,
    double max_sensor_reset_position, double sensor_reset_radius,
    double weight_position, double weight_orientation, rclcpp::Clock::SharedPtr clock);
  ~ParticleFilter();
  const int num_particles;
  const double buffer_length;
  const bool estimate_3d_pose;
  const double expansion_reset_ess_threashold;
  const double max_expansion_orientation;
  const double max_expantion_position;
  const double sensor_reset_ess_threashold;
  const double max_sensor_reset_orientation;
  const double max_sensor_reset_position;
  const double sensor_reset_radius;
  const double weight_position;
  const double weight_orientation;
  void updateTwist(geometry_msgs::msg::TwistStamped twist);
  void updatePose(geometry_msgs::msg::PoseStamped pose);
  boost::optional<geometry_msgs::msg::PoseStamped> estimateCurrentPose(rclcpp::Time stamp);
  boost::optional<geometry_msgs::msg::TwistStamped> getCurrentTwist()
  {
    return twist_estimator_->estimateTwist();
  }
  void setInitialPose(geometry_msgs::msg::PoseStamped pose);
  boost::optional<geometry_msgs::msg::PoseStamped> getInitialPose();
  std::vector<Particle> getParticles() {return particles_;}
  double getEffectiveSampleSize();

private:
  double getTotalWeights();
  void normalizeWeights();
  void expansionReset();
  void sensorReset(geometry_msgs::msg::PoseStamped pose);
  bool checkQuaternion(geometry_msgs::msg::Quaternion quat);
  void resampling();
  std::map<std::string, double> twist_weights_;
  std::map<std::string, double> point_weights_;
  std::vector<Particle> particles_;
  boost::optional<geometry_msgs::msg::PoseStamped> current_pose_;
  boost::optional<geometry_msgs::msg::PoseStamped> initial_pose_;
  std::random_device seed_gen_;
  std::default_random_engine engine_;
  std::normal_distribution<> position_dist_;
  std::normal_distribution<> rotation_dist_;
  std::mt19937 mt_;
  std::uniform_real_distribution<double> uniform_dist_;
  data_buffer::PoseStampedDataBuffer pose_buf_;
  data_buffer::TwistStampedDataBuffer twist_buf_;
  std::unique_ptr<TwistEstimator> twist_estimator_;
};
}  // namespace pf_localization

#endif  // PF_LOCALIZATION__PARTICLE_FILTER_HPP_


text:
#pragma once
/**
   @file StateMachine.hpp
   @brief State machine declarations.
*/

#include <future>
#include <memory>

#include <boost/log/trivial.hpp>
#include <boost/mpl/list.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/custom_reaction.hpp>
#include <boost/statechart/deferral.hpp>

#include "yaml-cpp/yaml.h"
#include "mimir/StateMachineFwd.hpp"

namespace mimir { namespace control {
    class CommandResponder;
    class StateNotifier;
  } }
namespace mimir { class IAlgorithm; }
namespace mpl = boost::mpl;

namespace mimir
{

  /**
     @brief State machine for the algorithm.

     The core program logic is implemented an asynchronous state machine. The state
     diagram below describes it. Its main purpose is to call the functions of an
     IAlgorithm implementation according to a set pattern.

     \rst
     .. uml::
       :align: center

       !include ../static/style.puml
       skinparam backgroundColor white
       [*] -> Standby : DdsTriad(..)

       state Standby
       state ShutDown
       ShutDown: entry / post(EvKill)
       ShutDown: exit / terminate()
       state Running {
       state Initializing
       state Evaluating
       state Waiting
       [*] -do-> Initializing : AlgorithmCreator(..)

       }
       Standby -do-> Running : EvStart
       Standby -ri-> ShutDown : EvKill
       Standby -up-> Standby : EvTimeout
       ShutDown --> [*] : EvKill
       Running -up-> Standby : EvStop || EvInterrupt
       Running -do-> ShutDown : EvKill || EvError || exception_thrown
       Initializing : entry / algorithm->initialize(..)
       Initializing -do-> Evaluating : EvReady
       Evaluating --> Waiting : EvReady
       Evaluating : entry / algorithm->solve(..)
       Waiting -do-> Evaluating : EvTimeout
       Waiting : entry / algorithm->timer(..)
     \endrst

  */
  struct StateMachine : bsc::asynchronous_state_machine
  <
    StateMachine,
    Standby,
    bsc::fifo_scheduler<>,
    std::allocator<void>,
    bsc::exception_translator<>
    >
  {
    /**
       @brief Constructor for state machine

       The constructor creates instances of DDS-related stuff, such as
       + DdsTriad : Initialized domain participant with publisher and subscriber instances.
       + CommandResponder : Class for interacting with other programs via DDS.
       + StateNotifier : Class that notifies subscribers of which state the state machine is in.

       @param [in] ctx Context construct needed for the asynchronous state machine
       @param [in] config YAML config, user provided configuration file
       @param [in] notify_others Reference to external boolean for inter-thread notification of living state machine.
    */
    StateMachine(my_context ctx, const YAML::Node& config, std::atomic<bool>& notify_others);
    /// Destructor.
    ~StateMachine();
    class DdsTriad;
  public:
    /// Pointer to the DdsTriad.
    DdsTriad * Dds();
    /// Pointer to the StateNotifier.
    control::StateNotifier * Notifier(){ return m_notifier.get(); }
    /// Reference to YAML configuration.
    const YAML::Node & Config(){ return m_config; }
  private:
    //virtual void initiate_impl();
    std::unique_ptr<DdsTriad> m_dds; ///< Instance of participant, publisher and subscriber
    std::unique_ptr<control::CommandResponder> m_responder;
    std::unique_ptr<control::StateNotifier> m_notifier;
    std::atomic<bool>& m_notify_others; ///< External boolean to notify others of terminated state machine.
    const YAML::Node m_config; ///< YAML configuration for state machine and algorithm.
  };

  /// The state machine is in standby, not running algorithm.
  struct Standby : bsc::state< Standby, StateMachine >
  {
    typedef mpl::list
    <
      bsc::transition< EvStart, Running >,
      bsc::transition< EvKill, ShutDown >,
      bsc::custom_reaction< EvTimeout >
      > reactions; ///< Admissible reactions for the state.

    /// Constructor.
    Standby(my_context ctx);
    /// Destructor.
    ~Standby();
    /// Custom reaction (extra function calls) in the event of EvTimeout.
    bsc::result react(const EvTimeout &);
  };

  /// The state machine is shutdown, cleaning up before quitting application.
  struct ShutDown : bsc::state< ShutDown, StateMachine >
  {
    typedef mpl::list
    <
      bsc::custom_reaction< EvKill >
      > reactions; ///< Admissible reactions for the state.

    /// Constructor.
    ShutDown(my_context ctx);
    /// Destructor.
    ~ShutDown();
    /// Custom reaction (extra function calls) in the event of EvKill.
    bsc::result react(const EvKill &);
  };

  /// Super state for running algorithm.
  struct Running : bsc::state< Running, StateMachine, Initializing >
  {
    typedef mpl::list
    <
      bsc::transition< EvStop, Standby >,
      bsc::transition< EvKill, ShutDown >,
      bsc::transition< EvError, ShutDown >,
      bsc::transition< EvInterrupt, Standby >,
      bsc::custom_reaction< bsc::exception_thrown >
      > reactions; ///< Admissible reactions for the state.

    /**
       @brief Constructor for Running state

       This state calls mimir::AlgorithmCreator() by passing configuration and other
       arguments. The instance of the IAlgorithm is held by the Running state and is in
       scope for nested states too.
    */
    Running(my_context ctx);
    /// Destructor.
    ~Running();
    /// Handling of exception, which currently is posting to log and shut down.
    bsc::result react(const bsc::exception_thrown &);
    /// Pointer to algorithm instance.
    mimir::IAlgorithm* Algorithm();

  private:
    std::unique_ptr<mimir::IAlgorithm> m_algorithm; ///< Pointer to algorithm interface implementation.
  };

  /// The state machine is initializing the algorithm.
  struct Initializing : bsc::state< Initializing, Running >
  {
    typedef mpl::list
    <
      bsc::custom_reaction< EvReady >
      > reactions; ///< Admissible reactions for the state.

    /// Constructor.
    Initializing(my_context ctx);
    /// Destructor.
    ~Initializing();
    /// Needed to "retrieve void result of future".
    bsc::result react(const EvReady &);

  private:
    std::future<void> m_future; ///< Mechanism to get result of async call. Needs to exist until call is done.
    std::atomic<bool> m_canceled; ///< Canceled variable, which is read in the async call.
  };

  /// The state machine is evaluating/solving algorithm.
  struct Evaluating : bsc::state< Evaluating, Running >
  {
    typedef mpl::list
    <
      bsc::custom_reaction< EvReady >
      > reactions; ///< Admissible reactions for the state.

    /// Constructor.
    Evaluating(my_context ctx);
    /// Destructor.
    ~Evaluating();
    /// Needed to "retrieve void result of future".
    bsc::result react(const EvReady &);

  private:
    std::future<void> m_future; ///< Mechanism to get result of async call. Needs to exist until call is done.
    std::atomic<bool> m_canceled; ///< Canceled variable, which is read in the async call.
  };

  /// The state machine is waiting for a timer to timeout.
  struct Waiting : bsc::state< Waiting, Running >
  {
    typedef mpl::list
    <
      bsc::transition< EvTimeout, Evaluating >
      > reactions; ///< Admissible reactions for the state.

    /// Constructor.
    Waiting(my_context ctx);
    /// Destructor.
    ~Waiting();

  private:
    std::future<void> m_future; ///< Mechanism to get result of async call. Needs to exist until call is done.
    std::atomic<bool> m_canceled; ///< Canceled variable, which is read in the async call.
  };

}

max_stars_repo_name: sintef-ocean/mimir

max_issues_repo_name: sintef-ocean/mimir

max_forks_repo_name: sintef-ocean/mimir


text:
#define BOOST_TEST_DYN_LINK

#include "fixtures.hpp"

#include <boost/test/parameterized_test.hpp>
#include <boost/test/unit_test.hpp>
#include <testmatch/enums.hpp>
#include <testmatch/pregame.hpp>

using namespace boost::unit_test;

BOOST_AUTO_TEST_SUITE(test_tossresult)

// Fixtures
struct F : public F_TeamAus, F_TeamNZ {
    F() {
        ts1 = {&nz, &aus, bat};
        ts2 = {&nz, &aus, field};
    };
    ~F(){};

    TossResult ts1, ts2;
};

BOOST_FIXTURE_TEST_CASE(test_getters, F) {
    BOOST_TEST(ts1.get_bat_team() == &nz);
    BOOST_TEST(ts1.get_bowl_team() == &aus);

    BOOST_TEST(ts2.get_bat_team() == &aus);
    BOOST_TEST(ts2.get_bowl_team() == &nz);
}

BOOST_FIXTURE_TEST_CASE(test_string, F) {
    BOOST_TEST(std::string(ts1) ==
               "New Zealand won the toss and elected to bat");
    BOOST_TEST(std::string(ts2) ==
               "New Zealand won the toss and elected to field");
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: LiamBlake/TestMatch-Backend

max_issues_repo_name: LiamBlake/TestMatch

max_forks_repo_name: LiamBlake/TestMatch


text:
#include <asio_uring/accept.hpp>

#include <cstdint>
#include <cstring>
#include <system_error>
#include <asio_uring/fd.hpp>
#include <boost/endian/conversion.hpp>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <sys/types.h>

#include <catch2/catch.hpp>

namespace asio_uring::tests {
namespace {

TEST_CASE("accept",
          "[accept]")
{
  fd listen(::socket(AF_INET,
                     SOCK_STREAM,
                     0));
  auto result = ::fcntl(listen.native_handle(),
                        F_GETFL);
  REQUIRE(result >= 0);
  result = ::fcntl(listen.native_handle(),
                   F_SETFL,
                   result | O_NONBLOCK);
  REQUIRE(result == 0);
  result = ::fcntl(listen.native_handle(),
                   F_GETFL);
  REQUIRE(result >= 0);
  REQUIRE((result & O_NONBLOCK) != 0);
  ::sockaddr_in addr;
  std::memset(&addr,
              0,
              sizeof(addr));
  addr.sin_family = AF_INET;
  std::uint32_t ip = 127;
  ip <<= 8;
  ip <<= 8;
  ip <<= 8;
  ip |= 1;
  boost::endian::native_to_big_inplace(ip);
  addr.sin_addr.s_addr = ip;
  result = ::bind(listen.native_handle(),
                  reinterpret_cast<const ::sockaddr*>(&addr),
                  sizeof(addr));
  REQUIRE(result == 0);
  ::socklen_t addr_len = sizeof(addr);
  result = ::getsockname(listen.native_handle(),
                         reinterpret_cast<::sockaddr*>(&addr),
                         &addr_len);
  REQUIRE(result == 0);
  REQUIRE(addr.sin_port != 0);
  result = ::listen(listen.native_handle(),
                    1);
  REQUIRE(result == 0);
  fd connect(::socket(AF_INET,
                      SOCK_STREAM,
                      0));
  result = ::connect(connect.native_handle(),
                     reinterpret_cast<const ::sockaddr*>(&addr),
                     sizeof(addr));
  REQUIRE(result == 0);
  ::sockaddr_in accepted_address;
  auto ec = make_error_code(std::errc::not_enough_memory);
  auto accepted = accept(listen.native_handle(),
                         accepted_address,
                         ec);
  REQUIRE_FALSE(ec);
  REQUIRE(accepted);
  CHECK(accepted_address.sin_family == addr.sin_family);
  CHECK(accepted_address.sin_addr.s_addr == addr.sin_addr.s_addr);
  result = ::fcntl(accepted->native_handle(),
                   F_GETFL);
  REQUIRE(result >= 0);
  REQUIRE((result & O_NONBLOCK) != 0);
}

TEST_CASE("accept binary",
          "[accept]")
{
  fd listen(::socket(AF_INET,
                     SOCK_STREAM,
                     0));
  auto result = ::fcntl(listen.native_handle(),
                        F_GETFL);
  REQUIRE(result >= 0);
  result = ::fcntl(listen.native_handle(),
                   F_SETFL,
                   result | O_NONBLOCK);
  REQUIRE(result == 0);
  result = ::fcntl(listen.native_handle(),
                   F_GETFL);
  REQUIRE(result >= 0);
  REQUIRE((result & O_NONBLOCK) != 0);
  ::sockaddr_in addr;
  std::memset(&addr,
              0,
              sizeof(addr));
  addr.sin_family = AF_INET;
  std::uint32_t ip = 127;
  ip <<= 8;
  ip <<= 8;
  ip <<= 8;
  ip |= 1;
  boost::endian::native_to_big_inplace(ip);
  addr.sin_addr.s_addr = ip;
  result = ::bind(listen.native_handle(),
                  reinterpret_cast<const ::sockaddr*>(&addr),
                  sizeof(addr));
  REQUIRE(result == 0);
  ::socklen_t addr_len = sizeof(addr);
  result = ::getsockname(listen.native_handle(),
                         reinterpret_cast<::sockaddr*>(&addr),
                         &addr_len);
  REQUIRE(result == 0);
  REQUIRE(addr.sin_port != 0);
  result = ::listen(listen.native_handle(),
                    1);
  REQUIRE(result == 0);
  fd connect(::socket(AF_INET,
                      SOCK_STREAM,
                      0));
  result = ::connect(connect.native_handle(),
                     reinterpret_cast<const ::sockaddr*>(&addr),
                     sizeof(addr));
  REQUIRE(result == 0);
  auto ec = make_error_code(std::errc::not_enough_memory);
  auto accepted = accept(listen.native_handle(),
                         ec);
  REQUIRE_FALSE(ec);
  REQUIRE(accepted);
  result = ::fcntl(accepted->native_handle(),
                   F_GETFL);
  REQUIRE(result >= 0);
  REQUIRE((result & O_NONBLOCK) != 0);
}

TEST_CASE("accept bad file descriptor",
          "[accept]")
{
  ::sockaddr_in addr;
  std::error_code ec;
  accept(-1,
         addr,
         ec);
  CHECK(ec);
  CHECK(ec == std::error_code(EBADF,
                              std::generic_category()));
}

TEST_CASE("accept would block",
          "[accept]")
{
  fd listen(::socket(AF_INET,
                     SOCK_STREAM,
                     0));
  auto result = ::fcntl(listen.native_handle(),
                        F_GETFL);
  REQUIRE(result >= 0);
  result = ::fcntl(listen.native_handle(),
                   F_SETFL,
                   result | O_NONBLOCK);
  REQUIRE(result == 0);
  result = ::fcntl(listen.native_handle(),
                   F_GETFL);
  REQUIRE(result >= 0);
  REQUIRE((result & O_NONBLOCK) != 0);
  ::sockaddr_in addr;
  std::memset(&addr,
              0,
              sizeof(addr));
  addr.sin_family = AF_INET;
  std::uint32_t ip = 127;
  ip <<= 8;
  ip <<= 8;
  ip <<= 8;
  ip |= 1;
  boost::endian::native_to_big_inplace(ip);
  addr.sin_addr.s_addr = ip;
  result = ::bind(listen.native_handle(),
                  reinterpret_cast<const ::sockaddr*>(&addr),
                  sizeof(addr));
  REQUIRE(result == 0);
  result = ::listen(listen.native_handle(),
                    1);
  REQUIRE(result == 0);
  auto ec = make_error_code(std::errc::not_enough_memory);
  auto accepted = accept(listen.native_handle(),
                         addr,
                         ec);
  CHECK_FALSE(ec);
  CHECK_FALSE(accepted);
}

}
}

max_stars_repo_name: soumy/AsioUring

max_issues_repo_name: soumy/AsioUring

max_forks_repo_name: soumy/AsioUring


text:
/*
 *             Copyright Andrey Semashev 2018.
 * Distributed under the Boost Software License, Version 1.0.
 *    (See accompanying file LICENSE_1_0.txt or copy at
 *          http://www.boost.org/LICENSE_1_0.txt)
 */
/*!
 * \file   heap_memory_abi.cpp
 * \author Andrey Semashev
 * \date   10.03.2018
 *
 * \brief  This file contains ABI test for heap_memory.hpp
 */

#include <boost/winapi/heap_memory.hpp>
#include <windows.h>
#include "abi_test_tools.hpp"

int main()
{
#if BOOST_WINAPI_PARTITION_DESKTOP_SYSTEM
    BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(GetProcessHeaps);
#endif

    BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(GetProcessHeap);
    BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(HeapAlloc);
    BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(HeapFree);
    BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(HeapReAlloc);

#if BOOST_WINAPI_PARTITION_APP_SYSTEM
    BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(HeapCreate);
    BOOST_WINAPI_TEST_FUNCTION_SIGNATURE(HeapDestroy);
#endif

    return boost::report_errors();
}