<commit_before>#include <mlopen.h>
#include "test.hpp"
#include <vector>
#include <array>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <memory>
#include <utility>
#include <iostream>
#include <cmath>
#include <mlopen/tensor.hpp>
#include <mlopen/convolution.hpp>
#include <mlopen/returns.hpp>
#include <mlopen/each_args.hpp>
#include <limits>
#include <thread>

#include "network_data.hpp"

template<class F>
struct protect_fn
{
    F f;
    protect_fn(F x) : f(std::move(x))
    {}

    template<class... Ts>
    auto operator()(Ts&&... xs) const MLOPEN_RETURNS
    (f(std::forward<Ts>(xs)...));
};

template<class F>
protect_fn<F> protect(F f)
{
    return {std::move(f)};
}

template<class F>
void par_for(std::size_t n, F f)
{
    const auto threadsize = std::thread::hardware_concurrency();
    if (n < threadsize)
    {
        for(std::size_t i=0;i<n;i++) f(i);
    }
    else
    {
        std::vector<std::thread> threads(threadsize);
        const std::size_t grainsize = std::ceil(static_cast<double>(n) / threads.size());

        std::size_t work = 0;
        std::generate(threads.begin(), threads.end(), [&]
        {
            std::size_t start = work;
            std::size_t last = std::min(n, work+grainsize);
            assert((last - start) <= grainsize);
            assert((last - start) > 0);
            auto result = std::thread([&f, start, last]
            {
                for(std::size_t i=start;i<last;i++)
                {
                    f(i);
                }
            });
            work += grainsize;
            return result;
        });
        // TODO: Should be in destructor
        for(auto&& t:threads)
        {
            if (t.joinable()) t.join();
        }
    }
}

// Multidimensional for loop
struct ford_impl
{
    template<class F>
    void operator()(F f) const
    {
        f();
    }

    template<class F, class T, class... Ts>
    void operator()(F f, T x, Ts... xs) const
    {
        // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55914
        for(T i=0;i<x;i++)
        {
            (*this)([&](Ts... is)
            {
                f(i, is...);
            }, xs...);
        }
    }
};

template<class... Ts>
auto ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(ford_impl{}, std::placeholders::_1, xs...)
);

struct par_ford_impl
{
    template<class F, class... Ts>
    void operator()(F f, Ts... xs) const
    {
        using array_type = std::array<std::size_t, sizeof...(Ts)>;
        array_type lens = {{static_cast<std::size_t>(xs)...}};
        array_type strides;
        strides.fill(1);
        std::partial_sum(lens.rbegin(), lens.rend()-1, strides.rbegin()+1, std::multiplies<std::size_t>());
        auto size = std::accumulate(lens.begin(), lens.end(), 1, std::multiplies<std::size_t>());
        par_for(size, [&](std::size_t i)
        {
            array_type indices;
            std::transform(strides.begin(), strides.end(), lens.begin(), indices.begin(), [&](size_t stride, size_t len)
            {
                return (i / stride) % len;
            });
            mlopen::unpack(f, indices);
        });
    }
};

template<class... Ts>
auto par_ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(par_ford_impl{}, std::placeholders::_1, xs...)
);

template<class T>
struct tensor
{
    mlopen::TensorDescriptor desc;
    std::vector<T> data;

    tensor(int n, int c, int h, int w)
    : desc(mlopenFloat, {n,c,h,w}), data(n*c*h*w)
    {}

    tensor(mlopen::TensorDescriptor rhs)
    : desc(std::move(rhs))
    {
        data.resize(desc.GetElementSize());
    }

    template<class G>
    tensor& generate(G g) &
    {
        this->generate_impl(g);
        return *this;
    }

    template<class G>
    tensor&& generate(G g) &&
    {
        this->generate_impl(g);
        return std::move(*this);
    }

    template<class G>
    void generate_impl(G g)
    {
        auto iterator = data.begin();
        this->for_each([&](int i, int j, int k, int m)
        {
            assert(iterator < data.end());
            *iterator = g(i, j, k, m);
            ++iterator;
        });
    }

    template<class F>
    void for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        ford(n, c, h, w)(std::move(f));
    }

    template<class F>
    void par_for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        par_ford(n, c, h, w)(std::move(f));
    }

    T& operator()(int n, int c, int h, int w)
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }

    const T& operator()(int n, int c, int h, int w) const
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }
};

struct tensor_generate
{
    template<class Tensor, class G>
    Tensor&& operator()(Tensor&& t, G g) const
    {
        return std::forward<Tensor>(t.generate(g));
    }
};

template<class T>
tensor<T> get_output_tensor(const mlopen::ConvolutionDescriptor& filter, const tensor<T>& input, const tensor<T>& weights)
{
    return tensor<T>{filter.GetForwardOutputTensor(input.desc, weights.desc)};
}

template<class T>
std::vector<T> forward_conv(const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    int in_n, in_c, in_h, in_w;
    std::tie(in_n, in_c, in_h, in_w) = mlopen::tie4(input.desc.GetLengths());

    int wei_h, wei_w;
    std::tie(std::ignore, std::ignore, wei_h, wei_w) = mlopen::tie4(weights.desc.GetLengths());

    out.par_for_each([&](int o, int w, int i, int j)
    {
        const int in_off_h = i * filter.v;
        const int in_off_w = j * filter.u;

        T acc = bias;
        ford(in_c, wei_h, wei_w)([&](int k, int x, int y)
        {
            const int in_x = in_off_h - filter.pad_h + x;
            const int in_y = in_off_w - filter.pad_w + y;
            if(in_x >= 0 && in_x < in_h && in_y >= 0 && in_y < in_w) {
                acc += input(o, k, in_x, in_y) * weights(w, k, x, y);
            }
        });
        out(o, w, i, j) = acc;
    });
    return out.data;
}

template<class T>
std::vector<T> forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int /* bias */ = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    auto in_dev = handle.Write(input.data);
    auto wei_dev = handle.Write(weights.data);
    auto out_dev = handle.Create<T>(out.data.size());

    int ret_algo_count;
    mlopenConvAlgoPerf_t perf;

    int alpha = 1, beta = 1;

    filter.FindConvFwdAlgorithm(handle,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        out.desc,
        out_dev.get(),
        1,
        &ret_algo_count,
        &perf,
        mlopenConvolutionFastest,
        NULL,
        10,
        0); // MD: Not performing exhaustiveSearch by default for now

    filter.ConvolutionForward(handle,
        &alpha,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        mlopenConvolutionFwdAlgoDirect,
        &beta,
        out.desc,
        out_dev.get(),
        NULL,
        0);

    out.data = handle.Read<T>(out_dev, out.data.size());
    return out.data;
}

struct float_equal_fn
{
    template<class T>
    bool operator()(T x, T y) const
    {
        return std::fabs(x - y) < std::max(std::numeric_limits<T>::epsilon() * std::max(x, y), std::numeric_limits<T>::epsilon());
    }
};

template<class R1, class R2>
bool float_equal_range(R1&& r1, R2&& r2)
{
    return std::distance(r1.begin(), r1.end()) == std::distance(r2.begin(), r2.end()) &&
        std::equal(r1.begin(), r1.end(), r2.begin(), float_equal_fn{});
}

template<class R1, class R2, class Op>
float accumulate_difference(R1&& r1, R2&& r2, Op op)
{
    return std::inner_product(r1.begin(), r1.end(), r2.begin(), 0.0, op,
        [](float x, float y) { return std::fabs(x - y); }
    );
}

template<class T>
void verify_forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out_cpu = forward_conv(input, weights, filter, bias);
    auto out_gpu = forward_conv(handle, input, weights, filter, bias);
    int size = std::distance(out_cpu.begin(), out_cpu.end());
    CHECK(std::distance(out_cpu.begin(), out_cpu.end()) == std::distance(out_gpu.begin(), out_gpu.end()));
    if (!float_equal_range(out_cpu, out_gpu))
    {
        std::cout << "FAILED: " << std::endl;
        std::cout << "Input tensor: " << input.desc.ToString() << std::endl;
        std::cout << "Weights tensor: " << weights.desc.ToString() << std::endl;

        std::cout
            << "Average difference: "
            << (accumulate_difference(out_cpu, out_gpu, std::plus<float>()) / size)
            << std::endl;
        std::cout
            << "Max difference: "
            << (accumulate_difference(out_cpu, out_gpu, [](float x, float y) { return std::max(x, y); }))
            << std::endl;
    }
    // CHECK(out_cpu == out_gpu);
}

struct cross_args_apply
{
    template<class F, class T, class... Ts>
    void operator()(F f, T&& x, Ts&&... xs) const
    {
        mlopen::each_args(std::bind(f, std::forward<T>(x), std::placeholders::_1), std::forward<Ts>(xs)...);
    }
};

template<class F, class... Ts>
void cross_args(F f, Ts&&... xs)
{
    mlopen::each_args(
        std::bind(cross_args_apply{}, protect(std::move(f)), std::placeholders::_1, std::forward<Ts>(xs)...),
    std::forward<Ts>(xs)...);
}

template<class T>
struct verify_both
{
    template<class G1, class G2>
    void operator()(mlopen::Handle& handle, G1 g1, G2 g2) const
    {
        visit_network<T>([&](mlopen::TensorDescriptor input_desc, mlopen::TensorDescriptor weights_desc)
        {
            auto input = tensor<T>{std::move(input_desc)}.generate(g1);
            auto weights = tensor<T>{std::move(weights_desc)}.generate(g2);
            mlopen::ConvolutionDescriptor filter{1, 1};

            verify_forward_conv(handle, input, weights, filter);
        });
    }
};

template<class T, class... Gs>
void verify_all(mlopen::Handle& handle, Gs... gs)
{
    cross_args(
        std::bind(verify_both<T>{}, std::ref(handle), std::placeholders::_1, std::placeholders::_2),
        gs...);
}

template<class T, class G>
void verify_one(mlopen::Handle& handle, G g)
{
    auto input = tensor<T>{16, 32, 8, 8}.generate(g);
    auto weights = tensor<T>{64, 32, 5, 5}.generate(g);
    mlopen::ConvolutionDescriptor filter{1, 1};
    verify_forward_conv(handle, input, weights, filter);
}

int main() {
    mlopen::Handle handle;
    auto g0 = [](int, int, int, int) { return 0; };
    auto g1 = [](int, int, int, int) { return 1; };
    auto g_id = [](int, int, int h, int w) { return h == w ? 1 : 0; };
    auto g = [](int n, int c, int h, int w)
    {
        double x = (547*n+701*c+877*h+1049*w+173)%1223;
        return x/691.0;
    };
    (void)g0;
    (void)g1;
    (void)g_id;
    (void)g;
#if MLOPEN_TEST_ALL
    printf("verify_all\n");
    verify_all<float>(handle, g0,g1, g_id, g);
#else
    printf("verify_one\n");
    verify_one<float>(handle, g);
#endif
}
<commit_msg>Fix asserts for par for<commit_after>#include <mlopen.h>
#include "test.hpp"
#include <vector>
#include <array>
#include <iterator>
#include <algorithm>
#include <numeric>
#include <memory>
#include <utility>
#include <iostream>
#include <cmath>
#include <mlopen/tensor.hpp>
#include <mlopen/convolution.hpp>
#include <mlopen/returns.hpp>
#include <mlopen/each_args.hpp>
#include <limits>
#include <thread>

#include "network_data.hpp"

template<class F>
struct protect_fn
{
    F f;
    protect_fn(F x) : f(std::move(x))
    {}

    template<class... Ts>
    auto operator()(Ts&&... xs) const MLOPEN_RETURNS
    (f(std::forward<Ts>(xs)...));
};

template<class F>
protect_fn<F> protect(F f)
{
    return {std::move(f)};
}

template<class F>
void par_for(std::size_t n, F f)
{
    const auto threadsize = std::thread::hardware_concurrency();
    if (n < threadsize)
    {
        for(std::size_t i=0;i<n;i++) f(i);
    }
    else
    {
        std::vector<std::thread> threads(threadsize);
        const std::size_t grainsize = std::ceil(static_cast<double>(n) / threads.size());

        std::size_t work = 0;
        std::generate(threads.begin(), threads.end(), [&]
        {
            auto result = std::thread([&, work]
            {
                std::size_t start = work;
                std::size_t last = std::min(n, work+grainsize);
                for(std::size_t i=start;i<last;i++)
                {
                    f(i);
                }
            });
            work += grainsize;
            return result;
        });
        assert(work >= n);
        // TODO: Should be in destructor
        for(auto&& t:threads)
        {
            if (t.joinable()) t.join();
        }
    }
}

// Multidimensional for loop
struct ford_impl
{
    template<class F>
    void operator()(F f) const
    {
        f();
    }

    template<class F, class T, class... Ts>
    void operator()(F f, T x, Ts... xs) const
    {
        // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55914
        for(T i=0;i<x;i++)
        {
            (*this)([&](Ts... is)
            {
                f(i, is...);
            }, xs...);
        }
    }
};

template<class... Ts>
auto ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(ford_impl{}, std::placeholders::_1, xs...)
);

struct par_ford_impl
{
    template<class F, class... Ts>
    void operator()(F f, Ts... xs) const
    {
        using array_type = std::array<std::size_t, sizeof...(Ts)>;
        array_type lens = {{static_cast<std::size_t>(xs)...}};
        array_type strides;
        strides.fill(1);
        std::partial_sum(lens.rbegin(), lens.rend()-1, strides.rbegin()+1, std::multiplies<std::size_t>());
        auto size = std::accumulate(lens.begin(), lens.end(), 1, std::multiplies<std::size_t>());
        par_for(size, [&](std::size_t i)
        {
            array_type indices;
            std::transform(strides.begin(), strides.end(), lens.begin(), indices.begin(), [&](size_t stride, size_t len)
            {
                return (i / stride) % len;
            });
            mlopen::unpack(f, indices);
        });
    }
};

template<class... Ts>
auto par_ford(Ts... xs) MLOPEN_RETURNS
(
    std::bind(par_ford_impl{}, std::placeholders::_1, xs...)
);

template<class T>
struct tensor
{
    mlopen::TensorDescriptor desc;
    std::vector<T> data;

    tensor(int n, int c, int h, int w)
    : desc(mlopenFloat, {n,c,h,w}), data(n*c*h*w)
    {}

    tensor(mlopen::TensorDescriptor rhs)
    : desc(std::move(rhs))
    {
        data.resize(desc.GetElementSize());
    }

    template<class G>
    tensor& generate(G g) &
    {
        this->generate_impl(g);
        return *this;
    }

    template<class G>
    tensor&& generate(G g) &&
    {
        this->generate_impl(g);
        return std::move(*this);
    }

    template<class G>
    void generate_impl(G g)
    {
        auto iterator = data.begin();
        this->for_each([&](int i, int j, int k, int m)
        {
            assert(iterator < data.end());
            *iterator = g(i, j, k, m);
            ++iterator;
        });
    }

    template<class F>
    void for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        ford(n, c, h, w)(std::move(f));
    }

    template<class F>
    void par_for_each(F f) const
    {
        int n, c, h, w;
        std::tie(n, c, h, w) = mlopen::tie4(desc.GetLengths());
        par_ford(n, c, h, w)(std::move(f));
    }

    T& operator()(int n, int c, int h, int w)
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }

    const T& operator()(int n, int c, int h, int w) const
    {
        assert(this->desc.GetIndex(n, c, h, w) < data.size());
        return this->data[this->desc.GetIndex(n, c, h, w)];
    }
};

struct tensor_generate
{
    template<class Tensor, class G>
    Tensor&& operator()(Tensor&& t, G g) const
    {
        return std::forward<Tensor>(t.generate(g));
    }
};

template<class T>
tensor<T> get_output_tensor(const mlopen::ConvolutionDescriptor& filter, const tensor<T>& input, const tensor<T>& weights)
{
    return tensor<T>{filter.GetForwardOutputTensor(input.desc, weights.desc)};
}

template<class T>
std::vector<T> forward_conv(const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    int in_n, in_c, in_h, in_w;
    std::tie(in_n, in_c, in_h, in_w) = mlopen::tie4(input.desc.GetLengths());

    int wei_h, wei_w;
    std::tie(std::ignore, std::ignore, wei_h, wei_w) = mlopen::tie4(weights.desc.GetLengths());

    out.par_for_each([&](int o, int w, int i, int j)
    {
        const int in_off_h = i * filter.v;
        const int in_off_w = j * filter.u;

        T acc = bias;
        ford(in_c, wei_h, wei_w)([&](int k, int x, int y)
        {
            const int in_x = in_off_h - filter.pad_h + x;
            const int in_y = in_off_w - filter.pad_w + y;
            if(in_x >= 0 && in_x < in_h && in_y >= 0 && in_y < in_w) {
                acc += input(o, k, in_x, in_y) * weights(w, k, x, y);
            }
        });
        out(o, w, i, j) = acc;
    });
    return out.data;
}

template<class T>
std::vector<T> forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int /* bias */ = 0)
{
    auto out = get_output_tensor(filter, input, weights);

    auto in_dev = handle.Write(input.data);
    auto wei_dev = handle.Write(weights.data);
    auto out_dev = handle.Create<T>(out.data.size());

    int ret_algo_count;
    mlopenConvAlgoPerf_t perf;

    int alpha = 1, beta = 1;

    filter.FindConvFwdAlgorithm(handle,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        out.desc,
        out_dev.get(),
        1,
        &ret_algo_count,
        &perf,
        mlopenConvolutionFastest,
        NULL,
        10,
        0); // MD: Not performing exhaustiveSearch by default for now

    filter.ConvolutionForward(handle,
        &alpha,
        input.desc,
        in_dev.get(),
        weights.desc,
        wei_dev.get(),
        mlopenConvolutionFwdAlgoDirect,
        &beta,
        out.desc,
        out_dev.get(),
        NULL,
        0);

    out.data = handle.Read<T>(out_dev, out.data.size());
    return out.data;
}

struct float_equal_fn
{
    template<class T>
    bool operator()(T x, T y) const
    {
        return std::fabs(x - y) < std::max(std::numeric_limits<T>::epsilon() * std::max(x, y), std::numeric_limits<T>::epsilon());
    }
};

template<class R1, class R2>
bool float_equal_range(R1&& r1, R2&& r2)
{
    return std::distance(r1.begin(), r1.end()) == std::distance(r2.begin(), r2.end()) &&
        std::equal(r1.begin(), r1.end(), r2.begin(), float_equal_fn{});
}

template<class R1, class R2, class Op>
float accumulate_difference(R1&& r1, R2&& r2, Op op)
{
    return std::inner_product(r1.begin(), r1.end(), r2.begin(), 0.0, op,
        [](float x, float y) { return std::fabs(x - y); }
    );
}

template<class T>
void verify_forward_conv(mlopen::Handle& handle, const tensor<T>& input, const tensor<T>& weights, const mlopen::ConvolutionDescriptor& filter, int bias = 0)
{
    auto out_cpu = forward_conv(input, weights, filter, bias);
    auto out_gpu = forward_conv(handle, input, weights, filter, bias);
    int size = std::distance(out_cpu.begin(), out_cpu.end());
    CHECK(std::distance(out_cpu.begin(), out_cpu.end()) == std::distance(out_gpu.begin(), out_gpu.end()));
    if (!float_equal_range(out_cpu, out_gpu))
    {
        std::cout << "FAILED: " << std::endl;
        std::cout << "Input tensor: " << input.desc.ToString() << std::endl;
        std::cout << "Weights tensor: " << weights.desc.ToString() << std::endl;

        std::cout
            << "Average difference: "
            << (accumulate_difference(out_cpu, out_gpu, std::plus<float>()) / size)
            << std::endl;
        std::cout
            << "Max difference: "
            << (accumulate_difference(out_cpu, out_gpu, [](float x, float y) { return std::max(x, y); }))
            << std::endl;
    }
    // CHECK(out_cpu == out_gpu);
}

struct cross_args_apply
{
    template<class F, class T, class... Ts>
    void operator()(F f, T&& x, Ts&&... xs) const
    {
        mlopen::each_args(std::bind(f, std::forward<T>(x), std::placeholders::_1), std::forward<Ts>(xs)...);
    }
};

template<class F, class... Ts>
void cross_args(F f, Ts&&... xs)
{
    mlopen::each_args(
        std::bind(cross_args_apply{}, protect(std::move(f)), std::placeholders::_1, std::forward<Ts>(xs)...),
    std::forward<Ts>(xs)...);
}

template<class T>
struct verify_both
{
    template<class G1, class G2>
    void operator()(mlopen::Handle& handle, G1 g1, G2 g2) const
    {
        visit_network<T>([&](mlopen::TensorDescriptor input_desc, mlopen::TensorDescriptor weights_desc)
        {
            auto input = tensor<T>{std::move(input_desc)}.generate(g1);
            auto weights = tensor<T>{std::move(weights_desc)}.generate(g2);
            mlopen::ConvolutionDescriptor filter{1, 1};

            verify_forward_conv(handle, input, weights, filter);
        });
    }
};

template<class T, class... Gs>
void verify_all(mlopen::Handle& handle, Gs... gs)
{
    cross_args(
        std::bind(verify_both<T>{}, std::ref(handle), std::placeholders::_1, std::placeholders::_2),
        gs...);
}

template<class T, class G>
void verify_one(mlopen::Handle& handle, G g)
{
    auto input = tensor<T>{16, 32, 8, 8}.generate(g);
    auto weights = tensor<T>{64, 32, 5, 5}.generate(g);
    mlopen::ConvolutionDescriptor filter{1, 1};
    verify_forward_conv(handle, input, weights, filter);
}

int main() {
    mlopen::Handle handle;
    auto g0 = [](int, int, int, int) { return 0; };
    auto g1 = [](int, int, int, int) { return 1; };
    auto g_id = [](int, int, int h, int w) { return h == w ? 1 : 0; };
    auto g = [](int n, int c, int h, int w)
    {
        double x = (547*n+701*c+877*h+1049*w+173)%1223;
        return x/691.0;
    };
    (void)g0;
    (void)g1;
    (void)g_id;
    (void)g;
#if MLOPEN_TEST_ALL
    printf("verify_all\n");
    verify_all<float>(handle, g0,g1, g_id, g);
#else
    printf("verify_one\n");
    verify_one<float>(handle, g);
#endif
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qaccelerometer.h>

QTM_BEGIN_NAMESPACE

class QSignallingAccelerometerListener;

/*!
    \class QAccelerometerReading
    \ingroup sensors

    \preliminary
    \brief The QAccelerometerReading class represents one reading from the
           accelerometer.

    The accelerometer returns linear acceleration values along 3 axes.
    The scale of the values is meters per second squared. The axes are arranged as follows.

\code
             +z
              |
              |      +y
              |     /
              |----/----
             /| NOKIA  /|
            //|--/--- / |
           // | /   //  /
          //  |/   //  /
         //   '--------------- +x
        //       //  /
       //       //  /
      /---------/  /
     /    O    /  /
    /         /  /
    ----------  /
    |_________!/
\endcode

    A monoblock device sitting at rest, face up on a desk will experience
    the force of Earth's gravity as approximately -9.8 on the Z axis.
*/

/*!
    \fn QAccelerometerReading::QAccelerometerReading()
    \internal
*/

/*!
    \fn QAccelerometerReading::QAccelerometerReading(qtimestamp timestamp, qreal x, qreal y, qreal z)
    \internal
*/

/*!
    \fn QAccelerometerReading::QAccelerometerReading(const QAccelerometerReading &other)
    \internal
*/

/*!
    \fn QAccelerometerReading::~QAccelerometerReading()
    \internal
*/

/*!
    \fn QAccelerometerReading::timestamp() const

    Returns the time when the reading was made.
*/

/*!
    \fn QAccelerometerReading::x() const

    Returns the acceleration for the X axis.
*/

/*!
    \fn QAccelerometerReading::y() const

    Returns the acceleration for the Y axis.
*/

/*!
    \fn QAccelerometerReading::z() const

    Returns the acceleration for the Z axis.
*/

// =====================================================================

/*!
    \class QAccelerometerListener
    \ingroup sensors

    \preliminary
    \brief The QAccelerometerListener class provides an efficient
           callback facility for asynchronous notifications of
           acceleration changes.

    Since the accelerometer is typically accessed very frequently it may
    not by suitable to use signals and slots. The QAccelerometerListener
    interface provides a way for the sensor to notify your class that a
    new accelerometer reading is available more efficiently.
*/

/*!
    \internal
*/
QAccelerometerListener::QAccelerometerListener()
{
}

/*!
    Notifies any sensors that the listener is being destroyed.
*/
QAccelerometerListener::~QAccelerometerListener()
{
    if (m_sensor)
        m_sensor->setListener(0);
}

/*!
    \fn QAccelerometerListener::accelerationChanged(const QAccelerometerReading &reading)

    This function is called when a new accelerometer \a reading is available.
*/

/*!
    \internal
*/
void QAccelerometerListener::setSensor(QAccelerometer *sensor)
{
    m_sensor = sensor;
}

/*!
    \fn QAccelerometerListener::sensor() const
    \internal
*/

// =====================================================================

class QSignallingAccelerometerListener : public QObject, public QAccelerometerListener
{
    Q_OBJECT
public:
    QSignallingAccelerometerListener()
    {
    }

    void setSensor(QAccelerometer *_sensor)
    {
        if (sensor())
            disconnect(this, SIGNAL(accelerationChanged(QAccelerometerReading)), sensor(), SIGNAL(accelerationChanged(QAccelerometerReading)));
        QAccelerometerListener::setSensor(_sensor);
        if (_sensor)
            connect(this, SIGNAL(accelerationChanged(QAccelerometerReading)), _sensor, SIGNAL(accelerationChanged(QAccelerometerReading)));
        else
            delete this; // remove us automatically
    }

signals:
    void accelerationChanged(const QAccelerometerReading &reading);
};

// =====================================================================

/*!
    \class QAccelerometer
    \ingroup sensors

    \preliminary
    \brief The QAccelerometer class reports on linear acceleration
           along the X, Y and Z axes.

    The accelerometer returns acceleration values along 3 axes.
    The scale of the values is meters per second squared. The axes are arranged as follows.

\code
             +z
              |
              |      +y
              |     /
              |----/----
             /| NOKIA  /|
            //|--/--- / |
           // | /   //  /
          //  |/   //  /
         //   '--------------- +x
        //       //  /
       //       //  /
      /---------/  /
     /    O    /  /
    /         /  /
    ----------  /
    |_________!/
\endcode

    A monoblock device sitting at rest, face up on a desk will experience
    the force of Earth's gravity as approximately -9.8 on the Z axis.

    \sa QAccelerometerReading
*/

/*!
    Construct a sensor instance with specified \a parent.
    If the \a identifier is passed the sensor will connect to that
    specific sensor, otherwise the default will be used.
*/
QAccelerometer::QAccelerometer(QObject *parent, const QSensorId &identifier)
    : QSensor(parent)
    , m_listener(0)
{
    m_backend = static_cast<QAccelerometerBackend*>(connectToBackend(identifier));
    setListener(0);
}

/*!
    Destroy the sensor. Stops the sensor if it has not already been stopped.
*/
QAccelerometer::~QAccelerometer()
{
    stop();
    if (m_listener)
        m_listener->setSensor(0);
}

/*!
    \property QAccelerometer::currentReading
    \brief the current reading from the sensor.
*/

/*!
    \variable QAccelerometer::typeId
*/
const QString QAccelerometer::typeId("qt.Accelerometer");

/*!
    \fn QAccelerometer::type() const
    \reimp
*/

/*!
    Set the \a listener for the sensor. Pass 0 to clear a previously-set
    listener.
    The listener will be invoked every time a new reading is available.

    Note that the sensor does not take ownership of the listener although
    the listener interface will notify the accelerometer if it is destroyed.

    Also note that setting a listener will prevent the accelerationChanged()
    signal from being emitted.
*/
void QAccelerometer::setListener(QAccelerometerListener *listener)
{
    if (listener == m_listener)
        return;
    if (m_listener)
        m_listener->setSensor(0);
    if (listener)
        m_listener = listener;
    else
        m_listener = new QSignallingAccelerometerListener;
    m_listener->setSensor(this);
}

/*!
    \fn QAccelerometer::currentReading() const

    Returns the current ambient light reading.
*/

/*!
    \fn QAccelerometer::accelerationChanged(const QAccelerometerReading &reading)

    This signal may be emitted when a new accelerometer \a reading comes in.

    This signal is only emitted if no listener has been set. If a listener has been
    set via setListener() then this signal will not be emitted.

    Note that this signal should not be used if you are requesting
    high-frequency updates as signal delivery is quite slow.

    \sa setListener()
*/

/*!
    \fn QAccelerometer::backend() const
    \reimp
*/

#include "moc_qaccelerometer.cpp"
#include "qaccelerometer.moc"
QTM_END_NAMESPACE

<commit_msg>Note that accelerometer values measure the force acting on the phone.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <qaccelerometer.h>

QTM_BEGIN_NAMESPACE

class QSignallingAccelerometerListener;

/*!
    \class QAccelerometerReading
    \ingroup sensors

    \preliminary
    \brief The QAccelerometerReading class represents one reading from the
           accelerometer.

    The accelerometer returns linear acceleration values along 3 axes.
    Values measure the force acting on the phone, the scale of the values is meters per second
    squared. The axes are arranged as follows:

\code
             +z
              |
              |      +y
              |     /
              |----/----
             /| NOKIA  /|
            //|--/--- / |
           // | /   //  /
          //  |/   //  /
         //   '--------------- +x
        //       //  /
       //       //  /
      /---------/  /
     /    O    /  /
    /         /  /
    ----------  /
    |_________!/
\endcode

    A monoblock device sitting at rest, face up on a desk will experience
    the force of Earth's gravity as approximately -9.8 on the Z axis.
*/

/*!
    \fn QAccelerometerReading::QAccelerometerReading()
    \internal
*/

/*!
    \fn QAccelerometerReading::QAccelerometerReading(qtimestamp timestamp, qreal x, qreal y, qreal z)
    \internal
*/

/*!
    \fn QAccelerometerReading::QAccelerometerReading(const QAccelerometerReading &other)
    \internal
*/

/*!
    \fn QAccelerometerReading::~QAccelerometerReading()
    \internal
*/

/*!
    \fn QAccelerometerReading::timestamp() const

    Returns the time when the reading was made.
*/

/*!
    \fn QAccelerometerReading::x() const

    Returns the acceleration for the X axis.
*/

/*!
    \fn QAccelerometerReading::y() const

    Returns the acceleration for the Y axis.
*/

/*!
    \fn QAccelerometerReading::z() const

    Returns the acceleration for the Z axis.
*/

// =====================================================================

/*!
    \class QAccelerometerListener
    \ingroup sensors

    \preliminary
    \brief The QAccelerometerListener class provides an efficient
           callback facility for asynchronous notifications of
           acceleration changes.

    Since the accelerometer is typically accessed very frequently it may
    not by suitable to use signals and slots. The QAccelerometerListener
    interface provides a way for the sensor to notify your class that a
    new accelerometer reading is available more efficiently.
*/

/*!
    \internal
*/
QAccelerometerListener::QAccelerometerListener()
{
}

/*!
    Notifies any sensors that the listener is being destroyed.
*/
QAccelerometerListener::~QAccelerometerListener()
{
    if (m_sensor)
        m_sensor->setListener(0);
}

/*!
    \fn QAccelerometerListener::accelerationChanged(const QAccelerometerReading &reading)

    This function is called when a new accelerometer \a reading is available.
*/

/*!
    \internal
*/
void QAccelerometerListener::setSensor(QAccelerometer *sensor)
{
    m_sensor = sensor;
}

/*!
    \fn QAccelerometerListener::sensor() const
    \internal
*/

// =====================================================================

class QSignallingAccelerometerListener : public QObject, public QAccelerometerListener
{
    Q_OBJECT
public:
    QSignallingAccelerometerListener()
    {
    }

    void setSensor(QAccelerometer *_sensor)
    {
        if (sensor())
            disconnect(this, SIGNAL(accelerationChanged(QAccelerometerReading)), sensor(), SIGNAL(accelerationChanged(QAccelerometerReading)));
        QAccelerometerListener::setSensor(_sensor);
        if (_sensor)
            connect(this, SIGNAL(accelerationChanged(QAccelerometerReading)), _sensor, SIGNAL(accelerationChanged(QAccelerometerReading)));
        else
            delete this; // remove us automatically
    }

signals:
    void accelerationChanged(const QAccelerometerReading &reading);
};

// =====================================================================

/*!
    \class QAccelerometer
    \ingroup sensors

    \preliminary
    \brief The QAccelerometer class reports on linear acceleration
           along the X, Y and Z axes.

    The accelerometer returns acceleration values along 3 axes.
    The scale of the values is meters per second squared. The axes are arranged as follows.

\code
             +z
              |
              |      +y
              |     /
              |----/----
             /| NOKIA  /|
            //|--/--- / |
           // | /   //  /
          //  |/   //  /
         //   '--------------- +x
        //       //  /
       //       //  /
      /---------/  /
     /    O    /  /
    /         /  /
    ----------  /
    |_________!/
\endcode

    A monoblock device sitting at rest, face up on a desk will experience
    the force of Earth's gravity as approximately -9.8 on the Z axis.

    \sa QAccelerometerReading
*/

/*!
    Construct a sensor instance with specified \a parent.
    If the \a identifier is passed the sensor will connect to that
    specific sensor, otherwise the default will be used.
*/
QAccelerometer::QAccelerometer(QObject *parent, const QSensorId &identifier)
    : QSensor(parent)
    , m_listener(0)
{
    m_backend = static_cast<QAccelerometerBackend*>(connectToBackend(identifier));
    setListener(0);
}

/*!
    Destroy the sensor. Stops the sensor if it has not already been stopped.
*/
QAccelerometer::~QAccelerometer()
{
    stop();
    if (m_listener)
        m_listener->setSensor(0);
}

/*!
    \property QAccelerometer::currentReading
    \brief the current reading from the sensor.
*/

/*!
    \variable QAccelerometer::typeId
*/
const QString QAccelerometer::typeId("qt.Accelerometer");

/*!
    \fn QAccelerometer::type() const
    \reimp
*/

/*!
    Set the \a listener for the sensor. Pass 0 to clear a previously-set
    listener.
    The listener will be invoked every time a new reading is available.

    Note that the sensor does not take ownership of the listener although
    the listener interface will notify the accelerometer if it is destroyed.

    Also note that setting a listener will prevent the accelerationChanged()
    signal from being emitted.
*/
void QAccelerometer::setListener(QAccelerometerListener *listener)
{
    if (listener == m_listener)
        return;
    if (m_listener)
        m_listener->setSensor(0);
    if (listener)
        m_listener = listener;
    else
        m_listener = new QSignallingAccelerometerListener;
    m_listener->setSensor(this);
}

/*!
    \fn QAccelerometer::currentReading() const

    Returns the current ambient light reading.
*/

/*!
    \fn QAccelerometer::accelerationChanged(const QAccelerometerReading &reading)

    This signal may be emitted when a new accelerometer \a reading comes in.

    This signal is only emitted if no listener has been set. If a listener has been
    set via setListener() then this signal will not be emitted.

    Note that this signal should not be used if you are requesting
    high-frequency updates as signal delivery is quite slow.

    \sa setListener()
*/

/*!
    \fn QAccelerometer::backend() const
    \reimp
*/

#include "moc_qaccelerometer.cpp"
#include "qaccelerometer.moc"
QTM_END_NAMESPACE

<|endoftext|>


<commit_before>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
http://www.etlcpp.com

Copyright(c) 2014 jwellbelove

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 <UnitTest++/UnitTest++.h>

#include "murmurhash3.h" // The 'C' reference implementation.

#include <iterator>
#include <string>
#include <vector>
#include <stdint.h>

#include "../src/jenkins.h"
#include "../src/endian.h"

template <typename TIterator>
uint32_t jenkins32(TIterator begin, TIterator end)
{
  uint32_t hash = 0;

  while (begin != end)
  {
    hash += *begin++;
    hash += (hash << 10);
    hash ^= (hash >> 6);
  }

  hash += (hash << 3);
  hash ^= (hash >> 11);
  hash += (hash << 15);

  return hash;
}

template <typename TIterator>
uint64_t jenkins64(TIterator begin, TIterator end)
{
  uint64_t hash = 0;

  while (begin != end)
  {
    hash += *begin++;
    hash += (hash << 10);
    hash ^= (hash >> 6);
  }

  hash += (hash << 3);
  hash ^= (hash >> 11);
  hash += (hash << 15);

  return hash;
}

namespace
{
  SUITE(test_jenkins)
  {
    //*************************************************************************
    TEST(test_jenkins_32_constructor)
    {
      std::string data("123456789");

      uint32_t hash    = etl::jenkins<uint32_t>(data.begin(), data.end());
      uint32_t compare = jenkins32(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_32_add_values)
    {
      std::string data("123456789");

      etl::jenkins<uint32_t> jenkins_32_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        jenkins_32_calculator.add(data[i]);
      }

      uint32_t hash    = jenkins_32_calculator;
      uint32_t compare = jenkins32(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_32_add_range)
    {
      std::string data("123456789");

      etl::jenkins<uint32_t> jenkins_32_calculator;

      jenkins_32_calculator.add(data.begin(), data.end());

      uint32_t hash = jenkins_32_calculator.value();

      uint32_t compare = jenkins32(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_32_add_range_endian)
    {
      std::vector<uint8_t>  data1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
      std::vector<uint32_t> data2 = { 0x04030201, 0x08070605 };
      std::vector<uint8_t>  data3 = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };

      uint32_t hash1 = etl::jenkins<uint32_t>(data1.begin(), data1.end());
      uint32_t hash2 = etl::jenkins<uint32_t>((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      uint32_t hash3 = etl::jenkins<uint32_t>(data3.rbegin(), data3.rend());

      CHECK_EQUAL(hash1, hash2);
      CHECK_EQUAL(hash1, hash3);

      uint64_t compare1 = jenkins32(data1.begin(), data1.end());
      CHECK_EQUAL(compare1, hash1);

      uint64_t compare2 = jenkins32((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      CHECK_EQUAL(compare2, hash2);

      uint64_t compare3 = jenkins32(data3.rbegin(), data3.rend());
      CHECK_EQUAL(compare2, hash3);
    }

    //*************************************************************************
    TEST(test_jenkins_64_constructor)
    {
      std::string data("123456789");

      uint64_t hash = etl::jenkins<uint64_t>(data.begin(), data.end());
      uint64_t compare = jenkins64(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_64_add_values)
    {
      std::string data("123456789");

      etl::jenkins<uint64_t> jenkins_64_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        jenkins_64_calculator.add(data[i]);
      }

      uint64_t hash = jenkins_64_calculator;
      uint64_t compare = jenkins64(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_64_add_range)
    {
      std::string data("123456789");

      etl::jenkins<uint64_t> jenkins_64_calculator;

      jenkins_64_calculator.add(data.begin(), data.end());

      uint64_t hash = jenkins_64_calculator.value();

      uint64_t compare = jenkins64(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_64_add_range_endian)
    {
      std::vector<uint8_t>  data1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
      std::vector<uint32_t> data2 = { 0x04030201, 0x08070605 };
      std::vector<uint8_t>  data3 = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };

      uint64_t hash1 = etl::jenkins<uint64_t>(data1.begin(), data1.end());
      uint64_t hash2 = etl::jenkins<uint64_t>((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      uint64_t hash3 = etl::jenkins<uint64_t>(data3.rbegin(), data3.rend());
      CHECK_EQUAL(hash1, hash2);
      CHECK_EQUAL(hash1, hash3);

      uint64_t compare1 = jenkins64(data1.begin(), data1.end());
      CHECK_EQUAL(compare1, hash1);

      uint64_t compare2 = jenkins64((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      CHECK_EQUAL(compare2, hash2);

      uint64_t compare3 = jenkins64(data3.rbegin(), data3.rend());
      CHECK_EQUAL(compare2, hash3);
    }
  };
}

<commit_msg>Added test_jenkins_32_finalised_exception<commit_after>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
http://www.etlcpp.com

Copyright(c) 2014 jwellbelove

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 <UnitTest++/UnitTest++.h>

#include "murmurhash3.h" // The 'C' reference implementation.

#include <iterator>
#include <string>
#include <vector>
#include <stdint.h>

#include "../src/jenkins.h"
#include "../src/endian.h"

template <typename TIterator>
uint32_t jenkins32(TIterator begin, TIterator end)
{
  uint32_t hash = 0;

  while (begin != end)
  {
    hash += *begin++;
    hash += (hash << 10);
    hash ^= (hash >> 6);
  }

  hash += (hash << 3);
  hash ^= (hash >> 11);
  hash += (hash << 15);

  return hash;
}

template <typename TIterator>
uint64_t jenkins64(TIterator begin, TIterator end)
{
  uint64_t hash = 0;

  while (begin != end)
  {
    hash += *begin++;
    hash += (hash << 10);
    hash ^= (hash >> 6);
  }

  hash += (hash << 3);
  hash ^= (hash >> 11);
  hash += (hash << 15);

  return hash;
}

namespace
{
  SUITE(test_jenkins)
  {
    //*************************************************************************
    TEST(test_jenkins_32_constructor)
    {
      std::string data("123456789");

      uint32_t hash    = etl::jenkins<uint32_t>(data.begin(), data.end());
      uint32_t compare = jenkins32(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_32_add_values)
    {
      std::string data("123456789");

      etl::jenkins<uint32_t> jenkins_32_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        jenkins_32_calculator.add(data[i]);
      }

      uint32_t hash    = jenkins_32_calculator;
      uint32_t compare = jenkins32(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_32_add_range)
    {
      std::string data("123456789");

      etl::jenkins<uint32_t> jenkins_32_calculator;

      jenkins_32_calculator.add(data.begin(), data.end());

      uint32_t hash = jenkins_32_calculator.value();

      uint32_t compare = jenkins32(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_32_add_range_endian)
    {
      std::vector<uint8_t>  data1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
      std::vector<uint32_t> data2 = { 0x04030201, 0x08070605 };
      std::vector<uint8_t>  data3 = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };

      uint32_t hash1 = etl::jenkins<uint32_t>(data1.begin(), data1.end());
      uint32_t hash2 = etl::jenkins<uint32_t>((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      uint32_t hash3 = etl::jenkins<uint32_t>(data3.rbegin(), data3.rend());

      CHECK_EQUAL(hash1, hash2);
      CHECK_EQUAL(hash1, hash3);

      uint64_t compare1 = jenkins32(data1.begin(), data1.end());
      CHECK_EQUAL(compare1, hash1);

      uint64_t compare2 = jenkins32((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      CHECK_EQUAL(compare2, hash2);

      uint64_t compare3 = jenkins32(data3.rbegin(), data3.rend());
      CHECK_EQUAL(compare2, hash3);
    }

    //*************************************************************************
    TEST(test_jenkins_32_finalised_exception)
    {
      std::string data("123456789");

      etl::jenkins<uint32_t> j32;
      j32.add(data.begin(), data.end());
      uint32_t hash = j32;

      CHECK_THROW(j32.add(0), etl::hash_finalised);
    }

    //*************************************************************************
    TEST(test_jenkins_64_constructor)
    {
      std::string data("123456789");

      uint64_t hash = etl::jenkins<uint64_t>(data.begin(), data.end());
      uint64_t compare = jenkins64(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_64_add_values)
    {
      std::string data("123456789");

      etl::jenkins<uint64_t> jenkins_64_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        jenkins_64_calculator.add(data[i]);
      }

      uint64_t hash = jenkins_64_calculator;
      uint64_t compare = jenkins64(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_64_add_range)
    {
      std::string data("123456789");

      etl::jenkins<uint64_t> jenkins_64_calculator;

      jenkins_64_calculator.add(data.begin(), data.end());

      uint64_t hash = jenkins_64_calculator.value();

      uint64_t compare = jenkins64(data.begin(), data.end());

      CHECK_EQUAL(compare, hash);
    }

    //*************************************************************************
    TEST(test_jenkins_64_add_range_endian)
    {
      std::vector<uint8_t>  data1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
      std::vector<uint32_t> data2 = { 0x04030201, 0x08070605 };
      std::vector<uint8_t>  data3 = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };

      uint64_t hash1 = etl::jenkins<uint64_t>(data1.begin(), data1.end());
      uint64_t hash2 = etl::jenkins<uint64_t>((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      uint64_t hash3 = etl::jenkins<uint64_t>(data3.rbegin(), data3.rend());
      CHECK_EQUAL(hash1, hash2);
      CHECK_EQUAL(hash1, hash3);

      uint64_t compare1 = jenkins64(data1.begin(), data1.end());
      CHECK_EQUAL(compare1, hash1);

      uint64_t compare2 = jenkins64((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      CHECK_EQUAL(compare2, hash2);

      uint64_t compare3 = jenkins64(data3.rbegin(), data3.rend());
      CHECK_EQUAL(compare2, hash3);
    }
  };
}

<|endoftext|>


<commit_before><commit_msg>Bugfix: `printf` format specifier `%s` used with `std::vector<char>`.<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dlgejpg.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 21:04:42 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#include "dlgejpg.hxx"
#include "dlgejpg.hrc"
#include "strings.hrc"
#include <FilterConfigItem.hxx>

#define KEY_QUALITY     "Quality"
#define KEY_GRAYSCALES  "ColorMode"

/*************************************************************************
|*
|* Ctor
|*
\************************************************************************/

DlgExportEJPG::DlgExportEJPG( FltCallDialogParameter& rPara ) :
                ModalDialog         ( rPara.pWindow, ResId( DLG_EXPORT_JPG, rPara.pResMgr ) ),
                rFltCallPara        ( rPara ),
                aFiDescr            ( this, ResId( FI_DESCR ) ),
                aNumFldQuality      ( this, ResId( NUM_FLD_QUALITY ) ),
                aGrpQuality         ( this, ResId( GRP_QUALITY ) ),
                aRbGray             ( this, ResId( RB_GRAY ) ),
                aRbRGB              ( this, ResId( RB_RGB ) ),
                aGrpColors          ( this, ResId( GRP_COLORS ) ),
                aBtnOK              ( this, ResId( BTN_OK ) ),
                aBtnCancel          ( this, ResId( BTN_CANCEL ) ),
                aBtnHelp            ( this, ResId( BTN_HELP ) )
{
    FreeResource();
    String  aFilterConfigPath( RTL_CONSTASCII_USTRINGPARAM( "Office.Common/Filter/Graphic/Export/JPG" ) );
    pConfigItem = new FilterConfigItem( aFilterConfigPath, &rPara.aFilterData );

    // reading filter options
    sal_Int32 nQuality = pConfigItem->ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_QUALITY ) ), 75 );
    sal_Int32 nColorMode = pConfigItem->ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_GRAYSCALES ) ), 0 );
    aNumFldQuality.SetValue( nQuality );

    if ( nColorMode  )
        aRbGray.Check( sal_True );
    else
        aRbRGB.Check( sal_True );

    aBtnOK.SetClickHdl( LINK( this, DlgExportEJPG, OK ) );
}

/*************************************************************************
|*
|* Speichert eingestellte Werte in ini-Datei
|*
\************************************************************************/

IMPL_LINK( DlgExportEJPG, OK, void *, EMPTYARG )
{
    // Config-Parameter schreiben
    pConfigItem->WriteInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_QUALITY ) ), (sal_Int32)aNumFldQuality.GetValue() );
    pConfigItem->WriteInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_GRAYSCALES ) ), aRbGray.IsChecked() ? 1 : 0 );
    rFltCallPara.aFilterData = pConfigItem->GetFilterData();
    EndDialog( RET_OK );
    return 0;
}

DlgExportEJPG::~DlgExportEJPG()
{
    delete pConfigItem;
}

<commit_msg>INTEGRATION: CWS pchfix02 (1.6.92); FILE MERGED 2006/09/01 17:43:05 kaib 1.6.92.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dlgejpg.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-17 14:51:12 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_svtools.hxx"
#include "dlgejpg.hxx"
#include "dlgejpg.hrc"
#include "strings.hrc"
#include <FilterConfigItem.hxx>

#define KEY_QUALITY     "Quality"
#define KEY_GRAYSCALES  "ColorMode"

/*************************************************************************
|*
|* Ctor
|*
\************************************************************************/

DlgExportEJPG::DlgExportEJPG( FltCallDialogParameter& rPara ) :
                ModalDialog         ( rPara.pWindow, ResId( DLG_EXPORT_JPG, rPara.pResMgr ) ),
                rFltCallPara        ( rPara ),
                aFiDescr            ( this, ResId( FI_DESCR ) ),
                aNumFldQuality      ( this, ResId( NUM_FLD_QUALITY ) ),
                aGrpQuality         ( this, ResId( GRP_QUALITY ) ),
                aRbGray             ( this, ResId( RB_GRAY ) ),
                aRbRGB              ( this, ResId( RB_RGB ) ),
                aGrpColors          ( this, ResId( GRP_COLORS ) ),
                aBtnOK              ( this, ResId( BTN_OK ) ),
                aBtnCancel          ( this, ResId( BTN_CANCEL ) ),
                aBtnHelp            ( this, ResId( BTN_HELP ) )
{
    FreeResource();
    String  aFilterConfigPath( RTL_CONSTASCII_USTRINGPARAM( "Office.Common/Filter/Graphic/Export/JPG" ) );
    pConfigItem = new FilterConfigItem( aFilterConfigPath, &rPara.aFilterData );

    // reading filter options
    sal_Int32 nQuality = pConfigItem->ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_QUALITY ) ), 75 );
    sal_Int32 nColorMode = pConfigItem->ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_GRAYSCALES ) ), 0 );
    aNumFldQuality.SetValue( nQuality );

    if ( nColorMode  )
        aRbGray.Check( sal_True );
    else
        aRbRGB.Check( sal_True );

    aBtnOK.SetClickHdl( LINK( this, DlgExportEJPG, OK ) );
}

/*************************************************************************
|*
|* Speichert eingestellte Werte in ini-Datei
|*
\************************************************************************/

IMPL_LINK( DlgExportEJPG, OK, void *, EMPTYARG )
{
    // Config-Parameter schreiben
    pConfigItem->WriteInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_QUALITY ) ), (sal_Int32)aNumFldQuality.GetValue() );
    pConfigItem->WriteInt32( String( RTL_CONSTASCII_USTRINGPARAM( KEY_GRAYSCALES ) ), aRbGray.IsChecked() ? 1 : 0 );
    rFltCallPara.aFilterData = pConfigItem->GetFilterData();
    EndDialog( RET_OK );
    return 0;
}

DlgExportEJPG::~DlgExportEJPG()
{
    delete pConfigItem;
}

<|endoftext|>


<commit_before>/// @file
/// @author uentity
/// @date 22.06.2018
/// @brief Implementation of BS tree-related serialization
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include <bs/actor_common.h>
#include <bs/atoms.h>
#include <bs/kernel/radio.h>
#include <bs/log.h>
#include <bs/tree/tree.h>
#include <bs/serialize/serialize.h>
#include <bs/serialize/tree.h>
#include <bs/serialize/cafbind.h>

#include <fstream>

CAF_ALLOW_UNSAFE_MESSAGE_TYPE(blue_sky::tree::on_serialized_f)

NAMESPACE_BEGIN(blue_sky::tree)
using namespace kernel::radio;
/*-----------------------------------------------------------------------------
 *  tree serialization actor impl
 *-----------------------------------------------------------------------------*/
NAMESPACE_BEGIN()
///////////////////////////////////////////////////////////////////////////////
//  Tree FS archive
//
auto unite_errors(const std::vector<error>& errs) -> error {
	std::string reduced_er;
	for(const auto& er : errs) {
		if(er) {
			if(!reduced_er.empty()) reduced_er += '\n';
			reduced_er += er.what();
		}
	}
	return reduced_er.empty() ? success() : error::quiet(reduced_er);
}

auto save_fs(const link& root, const std::string& filename) -> error {
	// collect all errors happened
	auto errs = std::vector<error>{};
	if(auto er = error::eval_safe([&] {
		auto ar = tree_fs_output(filename);
		ar(root);
		//ar.serializeDeferments();
		errs = ar.wait_objects_saved(infinite);
	}))
		errs.push_back(er);

	return unite_errors(errs);
}

auto load_fs(link& root, const std::string& filename) -> error {
	// collect all errors happened
	auto errs = std::vector<error>{};
	if(auto er = error::eval_safe([&] {
		auto ar = tree_fs_input(filename, tree_fs_input::NodeLoad::Normal);
		ar(root);
		//ar.serializeDeferments();
		errs = ar.wait_objects_loaded(infinite);
	}))
		errs.push_back(er);

	return unite_errors(errs);
}

///////////////////////////////////////////////////////////////////////////////
//  generic archives
//
auto save_generic(const link& root, const std::string& filename, TreeArchive ar) -> error {
return error::eval_safe([&]() -> error {
	// open file for writing
	std::ofstream fs(
		filename,
		std::ios::out | std::ios::trunc |
			(ar == TreeArchive::Binary ? std::ios::binary : std::ios::openmode(0))
	);

	// dump link to JSON archive
	if(ar == TreeArchive::Binary) {
		cereal::PortableBinaryOutputArchive ja(fs);
		ja(root);
	}
	else {
		cereal::JSONOutputArchive ja(fs);
		ja(root);
	}
	return perfect;
}); }

auto load_generic(link& root, const std::string& filename, TreeArchive ar) -> error {
return error::eval_safe([&]() -> error {
	// open file for reading
	auto mode = std::ios::in;
	if(ar == TreeArchive::Binary) mode |= std::ios::binary;
	std::ifstream fs(
		filename,
		std::ios::in | (ar == TreeArchive::Binary ? std::ios::binary : std::ios::openmode(0))
	);

	// load link from JSON archive
	if(ar == TreeArchive::Binary) {
		cereal::PortableBinaryInputArchive ja(fs);
		ja(root);
	}
	else {
		cereal::JSONInputArchive ja(fs);
		ja(root);
	}
	return perfect;
}); }

///////////////////////////////////////////////////////////////////////////////
//  serial ator impl
//
auto save_actor(
	caf::event_based_actor* self, link root, std::string filename, TreeArchive ar,
	on_serialized_f cb
) -> caf::behavior {
	return {
		[ar, r = std::move(root), filename = std::move(filename), cb = std::move(cb)](a_apply) mutable
		-> error::box {
			// launch work
			auto er = ar == TreeArchive::FS ? save_fs(r, filename) : save_generic(r, filename, ar);
			// invoke callback
			if(cb) error::eval_safe([&]{ cb(std::move(r), er); });
			return er;
		}
	};
}

auto load_actor(
	caf::event_based_actor* self, std::string filename, TreeArchive ar,
	on_serialized_f cb
) -> caf::behavior {
	return {
		[ar, filename = std::move(filename), cb = std::move(cb)](a_apply) mutable
		-> link_or_errbox {
			// launch work
			link r;
			auto er = ar == TreeArchive::FS ? load_fs(r, filename) : load_generic(r, filename, ar);
			// invoke callback
			if(cb) error::eval_safe([&]{ cb(r, er); });
			if(er.ok())
				return r;
			else
				return tl::make_unexpected(std::move(er));
		}
	};
}

NAMESPACE_END()

/*-----------------------------------------------------------------------------
 *  tree save impl
 *-----------------------------------------------------------------------------*/
auto save_tree(link root, std::string filename, TreeArchive ar, timespan wait_for) -> error {
	//bsout() << "*** save_tree with {} timeout" <<
	//	(wait_for == infinite ? "infinite" : to_string(wait_for)) << bs_end;
	// launch worker in detached actor
	auto Af = caf::make_function_view(
		system().spawn<caf::spawn_options::detach_flag>(
			save_actor, std::move(root), std::move(filename), ar, on_serialized_f{}
		),
		wait_for == infinite ? caf::infinite : caf::duration{wait_for}
	);

	// wait for result
	return actorf<error>(Af, a_apply());
}

BS_API auto save_tree(
	on_serialized_f cb, link root, std::string filename, TreeArchive ar
) -> void {
	// [NOTE] spawn save in detached actor to prevent starvation
	auto A = system().spawn<caf::spawn_options::detach_flag>(
		save_actor, std::move(root), std::move(filename), ar, std::move(cb)
	);
	caf::anon_send(A, a_apply());
}

/*-----------------------------------------------------------------------------
 *  tree load impl
 *-----------------------------------------------------------------------------*/
auto load_tree(std::string filename, TreeArchive ar) -> link_or_err {
	//link r;
	//auto er = ar == TreeArchive::FS ? load_fs(r, filename) : load_generic(r, filename, ar);
	//if(er.ok())
	//	return r;
	//else
	//	return tl::make_unexpected(std::move(er));

	// launch worker in detached actor
	auto Af = caf::make_function_view(
		system().spawn<caf::spawn_options::detach_flag>(
			load_actor, std::move(filename), ar, on_serialized_f{}
		),
		caf::infinite
	);

	// wait for result
	return actorf<link_or_errbox>(Af, a_apply());
}

auto load_tree(
	on_serialized_f cb, std::string filename, TreeArchive ar
) -> void {
	// [NOTE] spawn save in detached actor to prevent starvation
	auto A = system().spawn<caf::spawn_options::detach_flag>(
		load_actor, std::move(filename), ar, std::move(cb)
	);
	caf::anon_send(A, a_apply());
}

NAMESPACE_END(blue_sky::tree)
<commit_msg>serial/tree: minor fixes<commit_after>/// @file
/// @author uentity
/// @date 22.06.2018
/// @brief Implementation of BS tree-related serialization
/// @copyright
/// This Source Code Form is subject to the terms of the Mozilla Public License,
/// v. 2.0. If a copy of the MPL was not distributed with this file,
/// You can obtain one at https://mozilla.org/MPL/2.0/

#include <bs/actor_common.h>
#include <bs/atoms.h>
#include <bs/kernel/radio.h>
#include <bs/log.h>
#include <bs/tree/tree.h>
#include <bs/serialize/serialize.h>
#include <bs/serialize/tree.h>
#include <bs/serialize/cafbind.h>

#include <fstream>

CAF_ALLOW_UNSAFE_MESSAGE_TYPE(blue_sky::tree::on_serialized_f)

NAMESPACE_BEGIN(blue_sky::tree)
using namespace kernel::radio;
/*-----------------------------------------------------------------------------
 *  tree serialization actor impl
 *-----------------------------------------------------------------------------*/
NAMESPACE_BEGIN()
///////////////////////////////////////////////////////////////////////////////
//  Tree FS archive
//
auto unite_errors(const std::vector<error>& errs) -> error {
	std::string reduced_er;
	for(const auto& er : errs) {
		if(er) {
			if(!reduced_er.empty()) reduced_er += '\n';
			reduced_er += er.what();
		}
	}
	return reduced_er.empty() ? success() : error::quiet(reduced_er);
}

auto save_fs(const link& root, const std::string& filename) -> error {
	// collect all errors happened
	auto errs = std::vector<error>{};
	if(auto er = error::eval_safe([&] {
		auto ar = tree_fs_output(filename);
		ar(root);
		//ar.serializeDeferments();
		errs = ar.wait_objects_saved(infinite);
	}))
		errs.push_back(er);

	return unite_errors(errs);
}

auto load_fs(link& root, const std::string& filename) -> error {
	// collect all errors happened
	auto errs = std::vector<error>{};
	if(auto er = error::eval_safe([&] {
		auto ar = tree_fs_input(filename, tree_fs_input::NodeLoad::Normal);
		ar(root);
		//ar.serializeDeferments();
		errs = ar.wait_objects_loaded(infinite);
	}))
		errs.push_back(er);

	return unite_errors(errs);
}

///////////////////////////////////////////////////////////////////////////////
//  generic archives
//
auto save_generic(const link& root, const std::string& filename, TreeArchive ar) -> error {
return error::eval_safe([&] {
	// open file for writing
	std::ofstream fs(
		filename,
		std::ios::out | std::ios::trunc |
			(ar == TreeArchive::Binary ? std::ios::binary : std::ios::openmode(0))
	);

	// dump link to JSON archive
	if(ar == TreeArchive::Binary) {
		cereal::PortableBinaryOutputArchive ja(fs);
		ja(root);
	}
	else {
		cereal::JSONOutputArchive ja(fs);
		ja(root);
	}
}); }

auto load_generic(link& root, const std::string& filename, TreeArchive ar) -> error {
return error::eval_safe([&] {
	// open file for reading
	std::ifstream fs(
		filename,
		std::ios::in | (ar == TreeArchive::Binary ? std::ios::binary : std::ios::openmode(0))
	);

	// load link from JSON archive
	if(ar == TreeArchive::Binary) {
		cereal::PortableBinaryInputArchive ja(fs);
		ja(root);
	}
	else {
		cereal::JSONInputArchive ja(fs);
		ja(root);
	}
}); }

///////////////////////////////////////////////////////////////////////////////
//  actor to launch jobe above and result processing callback
//
auto save_actor(
	caf::event_based_actor* self, link root, std::string filename, TreeArchive ar,
	on_serialized_f cb
) -> caf::behavior {
	return {
		[ar, r = std::move(root), filename = std::move(filename), cb = std::move(cb)](a_apply) mutable
		-> error::box {
			// launch work
			auto er = ar == TreeArchive::FS ? save_fs(r, filename) : save_generic(r, filename, ar);
			// invoke callback
			if(cb) error::eval_safe([&]{ cb(std::move(r), er); });
			return er;
		}
	};
}

auto load_actor(
	caf::event_based_actor* self, std::string filename, TreeArchive ar,
	on_serialized_f cb
) -> caf::behavior {
	return {
		[ar, filename = std::move(filename), cb = std::move(cb)](a_apply) mutable
		-> link_or_errbox {
			// launch work
			link r;
			auto er = ar == TreeArchive::FS ? load_fs(r, filename) : load_generic(r, filename, ar);
			// invoke callback
			if(cb) error::eval_safe([&]{ cb(r, er); });
			if(er.ok())
				return r;
			else
				return tl::make_unexpected(std::move(er));
		}
	};
}

NAMESPACE_END()

/*-----------------------------------------------------------------------------
 *  tree save impl
 *-----------------------------------------------------------------------------*/
auto save_tree(link root, std::string filename, TreeArchive ar, timespan wait_for) -> error {
	//bsout() << "*** save_tree with {} timeout" <<
	//	(wait_for == infinite ? "infinite" : to_string(wait_for)) << bs_end;
	// launch worker in detached actor
	return actorf<error>(
		system().spawn<caf::detached>(
			save_actor, std::move(root), std::move(filename), ar, on_serialized_f{}
		),
		wait_for, a_apply()
	);
}

BS_API auto save_tree(
	on_serialized_f cb, link root, std::string filename, TreeArchive ar
) -> void {
	// [NOTE] spawn save in detached actor to prevent starvation
	auto A = system().spawn<caf::detached>(
		save_actor, std::move(root), std::move(filename), ar, std::move(cb)
	);
	caf::anon_send(A, a_apply());
}

/*-----------------------------------------------------------------------------
 *  tree load impl
 *-----------------------------------------------------------------------------*/
auto load_tree(std::string filename, TreeArchive ar) -> link_or_err {
	//link r;
	//auto er = ar == TreeArchive::FS ? load_fs(r, filename) : load_generic(r, filename, ar);
	//if(er.ok())
	//	return r;
	//else
	//	return tl::make_unexpected(std::move(er));

	// launch worker in detached actor
	return actorf<link_or_errbox>(
		system().spawn<caf::spawn_options::detach_flag>(
			load_actor, std::move(filename), ar, on_serialized_f{}
		),
		infinite, a_apply()
	);
}

auto load_tree(
	on_serialized_f cb, std::string filename, TreeArchive ar
) -> void {
	// [NOTE] spawn save in detached actor to prevent starvation
	auto A = system().spawn<caf::detached>(
		load_actor, std::move(filename), ar, std::move(cb)
	);
	caf::anon_send(A, a_apply());
}

NAMESPACE_END(blue_sky::tree)
<|endoftext|>


<commit_before>
// (c) COPYRIGHT URI/MIT 1996
// Please read the full copyright statement in the file COPYRIGH.
//
// Authors:
//	jhrg,jimg	James Gallagher (jgallagher@gso.uri.edu)

// This is the source to `geturl'; a simple tool to exercise the Connect
// class. It can be used to get naked URLs as well as the DODS DAS and DDS
// objects.  jhrg.

// $Log: getdap.cc,v $
// Revision 1.16  1996/12/18 18:43:32  jimg
// Tried to fix the online help - maybe I succeeded?
//
// Revision 1.15  1996/11/27 22:12:33  jimg
// Expanded help to include all the verbose options.
// Added PERF macros to code around request_data() call.
//
// Revision 1.14  1996/11/20 00:37:47  jimg
// Modified -D option to correctly process the Asynchronous option.
//
// Revision 1.13  1996/11/16 00:20:47  jimg
// Fixed a bug where multiple urls failed.
//
// Revision 1.12  1996/10/31 22:24:05  jimg
// Fix the help message so that -D is not described as -A...
//
// Revision 1.11  1996/10/08 17:13:09  jimg
// Added test for the -D option so that a Ce can be supplied either with the
// -c option or using a ? at the end of the URL.
//
// Revision 1.10  1996/09/19 16:53:35  jimg
// Added code to process sequences correctly when given the -D (get data)
// option.
//
// Revision 1.9  1996/09/05 16:28:06  jimg
// Added a new option to geturl, -D, which uses the Connect::request_data
// member function to get data. Thus -a, -d and -D can be used to get the
// das, dds and data from a DODS server. Because the request_data member
// function requires a constraint expression I also added the option -c; this
// option takes as a single argument a constraint expression and passes it to
// the request_data member function. You must use -c <expr> with -D.
//
// Revision 1.8  1996/08/13 20:13:36  jimg
// Added __unused__ to definition of char rcsid[].
// Added code so that local `URLs' are skipped.
//
// Revision 1.7  1996/06/22 00:11:20  jimg
// Modified to accomodate the new Gui class.
//
// Revision 1.6  1996/06/18 23:55:33  jimg
// Added support for the GUI progress indicator.
//
// Revision 1.5  1996/06/08 00:18:38  jimg
// Initialized vcode to null.
//
// Revision 1.4  1996/05/29 22:05:57  jimg
// Fixed up the copyright header.
//
// Revision 1.3  1996/05/28 17:35:40  jimg
// Fixed verbose arguments.
//
// Revision 1.2  1996/05/28 15:49:55  jimg
// Removed code that read from the stream after the das/dds parser built the
// internal object (since there was nothing in that stream after the parse
// geturl would always crash).
//
// Revision 1.1  1996/05/22 23:34:21  jimg
// First version. Built to test the new WWW code in the class Connect.
//

#include "config_dap.h"

static char rcsid[] __unused__ = {"$Id: getdap.cc,v 1.16 1996/12/18 18:43:32 jimg Exp $"};

#include <stdio.h>
#include <assert.h>

#include <GetOpt.h>
#include <String.h>

#include "Connect.h"

void
usage(String name)
{
    cerr << "Usage: " << name
	 << "[AdDa] [c <expr>] [v <codes>] [m <num>] <url> [<url> ...]"
	 << endl;
    cerr << "       " << "A: Use Connect's asynchronous mode." << endl;
    cerr << "       " << "d: For each URL, get the DODS DDS." << endl;
    cerr << "       " << "a: For each URL, get the DODS DAS." << endl;
    cerr << "       " << "D: For each URL, get the DODS Data." << endl;
    cerr << "       " << "g: Show the progress GUI." << endl;
    cerr << "       " << "c: <expr> is a contraint expression. Used with -D."
	 << endl;
    cerr << "       " << "   NB: You can use a `?' for the CE also." << endl;
    cerr << "       " << "v: <options> Verbose output; use -vd for default."
         << endl;
    cerr << "       " << "   a: show_anchor_trace." << endl;
    cerr << "       " << "   b: show_bind_trace." << endl;
    cerr << "       " << "   c: show_cache_trace." << endl;
    cerr << "       " << "   l: show_sgml_trace." << endl;
    cerr << "       " << "   m: show_mem_trace." << endl;
    cerr << "       " << "   p: show_protocol_trace." << endl;
    cerr << "       " << "   s: show_stream_trace." << endl;
    cerr << "       " << "   t: show_thread_trace." << endl;
    cerr << "       " << "   u: show_uri_trace." << endl;
    cerr << "       " << "m: Request the same URL <num> times." << endl;
    cerr << "       " << "Without A, use the synchronous mode." << endl;
    cerr << "       " << "Without d or a, print the URL." << endl;
}

bool
read_data(FILE *fp)
{
    char c;

    if (!fp) {
	cerr <<"Whoa!!! Null stream pointer." << endl;
	return false;
    }

    // Changed from a loop that used getc() to one that uses fread(). getc()
    // worked fine for transfers of text information, but *not* for binary
    // transfers. fread() will handle both.

    while (fread(&c, 1, 1, fp))
	printf("%c", c);	// stick with stdio

    return true;
}

int
main(int argc, char * argv[])
{
    GetOpt getopt (argc, argv, "AdaDgc:v:m:");
    int option_char;
    bool async = false;
    bool get_das = false;
    bool get_dds = false;
    bool get_data = false;
    bool gui = false;
    bool cexpr = false;
    bool verbose = false;
    bool multi = false;
    int times = 1;
    char *vcode = NULL;
    char *expr = NULL;
    int vopts = 0;

    while ((option_char = getopt()) != EOF)
	switch (option_char)
	    {
              case 'A': async = true; break;
              case 'd': get_dds = true; break;
	      case 'a': get_das = true; break;
	      case 'D': get_data = true; break;
	      case 'g': gui = true; break;
	      case 'c':
		cexpr = true; expr = getopt.optarg; break;
	      case 'v':
		verbose = true;
		vopts = strlen(getopt.optarg);
		if (vopts) {
		    vcode = new char[vopts + 1];
		    strcpy(vcode, getopt.optarg);
		}
		break;
	      case 'm': multi = true; times = atoi(getopt.optarg); break;
	      case 'h':
              case '?':
	      default:
		usage(argv[0]); exit(1); break;
	    }

    char c, *cc = vcode;
    if (verbose && vopts > 0)
	while ((c = *cc++))
	    switch (c) {
	      case 'a': WWWTRACE |= SHOW_ANCHOR_TRACE; break;
	      case 'b': WWWTRACE |= SHOW_BIND_TRACE; break;
	      case 'c': WWWTRACE |= SHOW_CACHE_TRACE; break;
	      case 'l': WWWTRACE |= SHOW_SGML_TRACE; break;
	      case 'm': WWWTRACE |= SHOW_MEM_TRACE; break;
	      case 'p': WWWTRACE |= SHOW_PROTOCOL_TRACE; break;
	      case 's': WWWTRACE |= SHOW_STREAM_TRACE; break;
	      case 't': WWWTRACE |= SHOW_THREAD_TRACE; break;
	      case 'u': WWWTRACE |= SHOW_URI_TRACE; break;
	      case 'd': break;
	      default:
		cerr << "Unrecognized verbose option: `" << c << "'" << endl;
		break;
	    }

    delete vcode;

    for (int i = getopt.optind; i < argc; ++i) {
	if (verbose)
	    cerr << "Fetching " << argv[i] << ":" << endl;

	String name = argv[i];
	Connect url(name);

	if (url.is_local()) {
	    cerr << "Skipping the URL `" << argv[i]
		 << "' because it lacks the `http' access protocol."
		 << endl;
	    continue;
	}

	if (get_das) {
	    for (int j = 0; j < times; ++j) {
		if (!url.request_das(gui))
		    exit(1);
		if (verbose)
		    cerr << "DAS:" << endl;
		url.das().print();
	    }
	}

	if (get_dds) {
	    for (int j = 0; j < times; ++j) {
		if (!url.request_dds(gui))
		    exit(1);
		if (verbose)
		    cerr << "DDS:" << endl;
		url.dds().print();
	    }
	}

	if (get_data) {
	    if (!(expr || name.contains("?"))) {
		cerr << "Must supply a constraint expression with -D."
		     << endl;
		exit(1);
	    }
	    for (int j = 0; j < times; ++j) {
		DDS &dds = url.request_data(expr, gui, async);

		cout << "The data:" << endl;
		for (Pix q = dds.first_var(); q; dds.next_var(q)) {
		    BaseType *v = dds.var(q);
		    switch (v->type()) {
			// Sequences present a special case because I let
			// their semantics get out of hand... jhrg 9/12/96
		      case dods_sequence_c:
			((Sequence *)v)->print_all_vals(cout, url.source());
			break;
		      default:
			PERF(cerr << "Deserializing: " << dds.var(q).name() \
			     << endl);
			if (async && !dds.var(q)->deserialize(url.source())) {
			    cerr << "Asynchronous read failure." << endl;
			    exit(1);
			}
			PERF(cerr << "Deserializing complete" << endl);
			dds.var(q)->print_val(cout);
			break;
		    }
		}
	    }
	}

	if (!get_das && !get_dds && !get_data) {
	    if (gui)
		url.gui()->show_gui(gui);
	    String url_string = argv[i];
	    for (int j = 0; j < times; ++j) {
		if (!url.fetch_url(url_string, async))
		    exit(1);
		FILE *fp = url.output();
		if (!read_data(fp))
		    exit(1);
		fclose(fp);
	    }
	}
    }
}
<commit_msg>Modified usage of request_data() to match new return type.<commit_after>
// (c) COPYRIGHT URI/MIT 1996
// Please read the full copyright statement in the file COPYRIGH.
//
// Authors:
//	jhrg,jimg	James Gallagher (jgallagher@gso.uri.edu)

// This is the source to `geturl'; a simple tool to exercise the Connect
// class. It can be used to get naked URLs as well as the DODS DAS and DDS
// objects.  jhrg.

// $Log: getdap.cc,v $
// Revision 1.17  1997/02/10 02:36:10  jimg
// Modified usage of request_data() to match new return type.
//
// Revision 1.16  1996/12/18 18:43:32  jimg
// Tried to fix the online help - maybe I succeeded?
//
// Revision 1.15  1996/11/27 22:12:33  jimg
// Expanded help to include all the verbose options.
// Added PERF macros to code around request_data() call.
//
// Revision 1.14  1996/11/20 00:37:47  jimg
// Modified -D option to correctly process the Asynchronous option.
//
// Revision 1.13  1996/11/16 00:20:47  jimg
// Fixed a bug where multiple urls failed.
//
// Revision 1.12  1996/10/31 22:24:05  jimg
// Fix the help message so that -D is not described as -A...
//
// Revision 1.11  1996/10/08 17:13:09  jimg
// Added test for the -D option so that a Ce can be supplied either with the
// -c option or using a ? at the end of the URL.
//
// Revision 1.10  1996/09/19 16:53:35  jimg
// Added code to process sequences correctly when given the -D (get data)
// option.
//
// Revision 1.9  1996/09/05 16:28:06  jimg
// Added a new option to geturl, -D, which uses the Connect::request_data
// member function to get data. Thus -a, -d and -D can be used to get the
// das, dds and data from a DODS server. Because the request_data member
// function requires a constraint expression I also added the option -c; this
// option takes as a single argument a constraint expression and passes it to
// the request_data member function. You must use -c <expr> with -D.
//
// Revision 1.8  1996/08/13 20:13:36  jimg
// Added __unused__ to definition of char rcsid[].
// Added code so that local `URLs' are skipped.
//
// Revision 1.7  1996/06/22 00:11:20  jimg
// Modified to accomodate the new Gui class.
//
// Revision 1.6  1996/06/18 23:55:33  jimg
// Added support for the GUI progress indicator.
//
// Revision 1.5  1996/06/08 00:18:38  jimg
// Initialized vcode to null.
//
// Revision 1.4  1996/05/29 22:05:57  jimg
// Fixed up the copyright header.
//
// Revision 1.3  1996/05/28 17:35:40  jimg
// Fixed verbose arguments.
//
// Revision 1.2  1996/05/28 15:49:55  jimg
// Removed code that read from the stream after the das/dds parser built the
// internal object (since there was nothing in that stream after the parse
// geturl would always crash).
//
// Revision 1.1  1996/05/22 23:34:21  jimg
// First version. Built to test the new WWW code in the class Connect.
//

#include "config_dap.h"

static char rcsid[] __unused__ = {"$Id: getdap.cc,v 1.17 1997/02/10 02:36:10 jimg Exp $"};

#include <stdio.h>
#include <assert.h>

#include <GetOpt.h>
#include <String.h>

#include "Connect.h"

void
usage(String name)
{
    cerr << "Usage: " << name
	 << "[AdDagV] [c <expr>] [t <codes>] [m <num>] <url> [<url> ...]"
	 << endl;
    cerr << "       " << "A: Use Connect's asynchronous mode." << endl;
    cerr << "       " << "d: For each URL, get the DODS DDS." << endl;
    cerr << "       " << "a: For each URL, get the DODS DAS." << endl;
    cerr << "       " << "D: For each URL, get the DODS Data." << endl;
    cerr << "       " << "g: Show the progress GUI." << endl;
    cerr << "       " << "V: Version." << endl;
    cerr << "       " << "c: <expr> is a contraint expression. Used with -D."
	 << endl;
    cerr << "       " << "   NB: You can use a `?' for the CE also." << endl;
    cerr << "       " << "t: <options> trace output; use -td for default."
         << endl;
    cerr << "       " << "   a: show_anchor_trace." << endl;
    cerr << "       " << "   b: show_bind_trace." << endl;
    cerr << "       " << "   c: show_cache_trace." << endl;
    cerr << "       " << "   l: show_sgml_trace." << endl;
    cerr << "       " << "   m: show_mem_trace." << endl;
    cerr << "       " << "   p: show_protocol_trace." << endl;
    cerr << "       " << "   s: show_stream_trace." << endl;
    cerr << "       " << "   t: show_thread_trace." << endl;
    cerr << "       " << "   u: show_uri_trace." << endl;
    cerr << "       " << "m: Request the same URL <num> times." << endl;
    cerr << "       " << "Without A, use the synchronous mode." << endl;
    cerr << "       " << "Without d or a, print the URL." << endl;
}

bool
read_data(FILE *fp)
{
    char c;

    if (!fp) {
	cerr <<"Whoa!!! Null stream pointer." << endl;
	return false;
    }

    // Changed from a loop that used getc() to one that uses fread(). getc()
    // worked fine for transfers of text information, but *not* for binary
    // transfers. fread() will handle both.

    while (fread(&c, 1, 1, fp))
	printf("%c", c);	// stick with stdio

    return true;
}

int
main(int argc, char * argv[])
{
    GetOpt getopt (argc, argv, "AdaDgVc:t:m:");
    int option_char;
    bool async = false;
    bool get_das = false;
    bool get_dds = false;
    bool get_data = false;
    bool gui = false;
    bool cexpr = false;
    bool verbose = false;
    bool trace = false;
    bool multi = false;
    int times = 1;
    char *tcode = NULL;
    char *expr = NULL;
    int topts = 0;

    while ((option_char = getopt()) != EOF)
	switch (option_char)
	    {
              case 'A': async = true; break;
              case 'd': get_dds = true; break;
	      case 'a': get_das = true; break;
	      case 'D': get_data = true; break;
	      case 'V': verbose = true; break;
	      case 'g': gui = true; break;
	      case 'c':
		cexpr = true; expr = getopt.optarg; break;
	      case 'v':
		trace = true;
		topts = strlen(getopt.optarg);
		if (topts) {
		    tcode = new char[topts + 1];
		    strcpy(tcode, getopt.optarg);
		}
		break;
	      case 'm': multi = true; times = atoi(getopt.optarg); break;
	      case 'h':
              case '?':
	      default:
		usage(argv[0]); exit(1); break;
	    }

    char c, *cc = tcode;
    if (trace && topts > 0)
	while ((c = *cc++))
	    switch (c) {
	      case 'a': WWWTRACE |= SHOW_ANCHOR_TRACE; break;
	      case 'b': WWWTRACE |= SHOW_BIND_TRACE; break;
	      case 'c': WWWTRACE |= SHOW_CACHE_TRACE; break;
	      case 'l': WWWTRACE |= SHOW_SGML_TRACE; break;
	      case 'm': WWWTRACE |= SHOW_MEM_TRACE; break;
	      case 'p': WWWTRACE |= SHOW_PROTOCOL_TRACE; break;
	      case 's': WWWTRACE |= SHOW_STREAM_TRACE; break;
	      case 't': WWWTRACE |= SHOW_THREAD_TRACE; break;
	      case 'u': WWWTRACE |= SHOW_URI_TRACE; break;
	      case 'd': break;
	      default:
		cerr << "Unrecognized trace option: `" << c << "'" << endl;
		break;
	    }

    delete tcode;

    for (int i = getopt.optind; i < argc; ++i) {
	if (verbose)
	    cerr << "Fetching " << argv[i] << ":" << endl;

	String name = argv[i];
	Connect url(name);

	if (url.is_local()) {
	    cerr << "Skipping the URL `" << argv[i]
		 << "' because it lacks the `http' access protocol."
		 << endl;
	    continue;
	}

	if (get_das) {
	    for (int j = 0; j < times; ++j) {
		if (!url.request_das(gui))
		    continue;
		if (verbose)
		    cerr << "DAS:" << endl;
		url.das().print();
	    }
	}

	if (get_dds) {
	    for (int j = 0; j < times; ++j) {
		if (!url.request_dds(gui))
		    continue;
		if (verbose)
		    cerr << "DDS:" << endl;
		url.dds().print();
	    }
	}

	if (get_data) {
	    if (!(expr || name.contains("?"))) {
		cerr << "Must supply a constraint expression with -D."
		     << endl;
		continue;
	    }
	    for (int j = 0; j < times; ++j) {
		DDS *dds = url.request_data(expr, gui, async);
		if (!dds) {
		    cerr << "Error reading data" << endl;
		    continue;
		}
		cout << "The data:" << endl;
		for (Pix q = dds->first_var(); q; dds->next_var(q)) {
		    BaseType *v = dds->var(q);
		    switch (v->type()) {
			// Sequences present a special case because I let
			// their semantics get out of hand... jhrg 9/12/96
		      case dods_sequence_c:
			((Sequence *)v)->print_all_vals(cout, url.source());
			break;
		      default:
			PERF(cerr << "Deserializing: " << dds.var(q).name() \
			     << endl);
			if (async && !dds->var(q)->deserialize(url.source())) {
			    cerr << "Asynchronous read failure." << endl;
			    exit(1);
			}
			PERF(cerr << "Deserializing complete" << endl);
			dds->var(q)->print_val(cout);
			break;
		    }
		}
	    }
	}

	if (!get_das && !get_dds && !get_data) {
	    if (gui)
		url.gui()->show_gui(gui);
	    String url_string = argv[i];
	    for (int j = 0; j < times; ++j) {
		if (!url.fetch_url(url_string, async))
		    continue;
		FILE *fp = url.output();
		if (!read_data(fp))
		    continue;
		fclose(fp);
	    }
	}
    }
}
<|endoftext|>