<commit_before>/*
 * Copyright (C) 2017 ScyllaDB
 */

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

#include "tests/test-utils.hh"

#include <seastar/core/thread.hh>

#include "cell_locking.hh"
#include "mutation.hh"
#include "schema_builder.hh"

static schema_ptr make_schema()
{
    return schema_builder("ks", "cf")
            .with_column("pk", bytes_type, column_kind::partition_key)
            .with_column("ck", bytes_type, column_kind::clustering_key)
            .with_column("s1", bytes_type, column_kind::static_column)
            .with_column("s2", bytes_type, column_kind::static_column)
            .with_column("s3", bytes_type, column_kind::static_column)
            .with_column("r1", bytes_type)
            .with_column("r2", bytes_type)
            .with_column("r3", bytes_type)
            .build();
}

static schema_ptr make_alternative_schema()
{
    return schema_builder("ks", "cf")
            .with_column("pk", bytes_type, column_kind::partition_key)
            .with_column("ck", bytes_type, column_kind::clustering_key)
            .with_column("s0", bytes_type, column_kind::static_column)
            .with_column("s1", bytes_type, column_kind::static_column)
            .with_column("s2.5", bytes_type, column_kind::static_column)
            .with_column("s3", bytes_type, column_kind::static_column)
            .with_column("r0", bytes_type)
            .with_column("r1", bytes_type)
            .with_column("r2.5", bytes_type)
            .with_column("r3", bytes_type)
            .build();
}

static schema_ptr make_schema_disjoint_with_others()
{
    return schema_builder("ks", "cf")
            .with_column("pk", bytes_type, column_kind::partition_key)
            .with_column("ck", bytes_type, column_kind::clustering_key)
            .with_column("s8", bytes_type, column_kind::static_column)
            .with_column("s9", bytes_type, column_kind::static_column)
            .with_column("r8", bytes_type)
            .with_column("r9", bytes_type)
            .build();
}

static data_value empty_value = data_value(to_bytes(""));

static db::timeout_clock::time_point no_timeout {
    db::timeout_clock::duration(std::numeric_limits<db::timeout_clock::duration::rep>::max())
};

static auto make_row(const sstring& key, std::initializer_list<sstring> cells) {
    return std::pair<sstring, std::initializer_list<sstring>>(key, cells);
}

static mutation make_mutation(schema_ptr s, const sstring& pk, std::initializer_list<sstring> static_cells,
                              std::initializer_list<std::pair<sstring, std::initializer_list<sstring>>> clustering_cells)
{
    auto m = mutation(s, partition_key::from_single_value(*s, to_bytes(pk)));
    for (auto&& c : static_cells) {
        m.set_static_cell(to_bytes(c), empty_value, api::new_timestamp());
    }
    for (auto&& r : clustering_cells) {
        auto ck = clustering_key::from_single_value(*s, to_bytes(r.first));
        for (auto&& c : r.second) {
            m.set_clustered_cell(ck, to_bytes(c), empty_value, api::new_timestamp());
        }
    }
    return m;
}

SEASTAR_TEST_CASE(test_simple_locking_cells) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m = make_mutation(s, "0", { "s1", "s3" }, {
            make_row("one", { "r1", "r2" }),
            make_row("two", { "r2", "r3" }),
        });

        auto l1 = cl.lock_cells(m.decorated_key(), partition_cells_range(m.partition()), no_timeout).get0();
        auto f2 = cl.lock_cells(m.decorated_key(), partition_cells_range(m.partition()), no_timeout);
        BOOST_REQUIRE(!f2.available());

        destroy(std::move(l1));
        destroy(f2.get0());
    });
}

SEASTAR_TEST_CASE(test_disjoint_mutations) {
    return seastar::async([&] {
        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m1 = make_mutation(s, "0", { "s1" }, {
                make_row("one", { "r1", "r2" }),
                make_row("two", { "r3" }),
        });
        auto m2 = make_mutation(s, "0", { "s2" }, {
                make_row("two", { "r1", "r2" }),
                make_row("one", { "r3" }),
        });

        auto m3 = mutation(s, partition_key::from_single_value(*s, to_bytes("1")));
        m3.partition() = mutation_partition(*s, m1.partition());

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
        auto l2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout).get0();
        auto l3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout).get0();
    });
}

SEASTAR_TEST_CASE(test_single_cell_overlap) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m1 = make_mutation(s, "0", { "s1" }, {
                make_row("one", { "r1", "r2" }),
                make_row("two", { "r3" }),
        });
        auto m2 = make_mutation(s, "0", { "s1" }, {
                make_row("two", { "r1", "r2" }),
                make_row("one", { "r3" }),
        });
        auto m3 = make_mutation(s, "0", { "s2" }, {
                make_row("two", { "r1" }),
                make_row("one", { "r2", "r3" }),
        });

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
        auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
        BOOST_REQUIRE(!f2.available());
        destroy(std::move(l1));
        auto l2 = f2.get0();
        auto f3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout);
        BOOST_REQUIRE(!f3.available());
        destroy(std::move(l2));
        auto l3 = f3.get0();
    });
}

SEASTAR_TEST_CASE(test_schema_change) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s1 = make_schema();
        auto s2 = make_alternative_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s1, cl_stats);

        auto m1 = make_mutation(s1, "0", { "s1", "s2", "s3"}, {
            make_row("one", { "r1", "r2", "r3" }),
        });

        // disjoint with m1
        auto m2 = make_mutation(s2, "0", { "s0", "s2.5"}, {
                make_row("one", { "r0", "r2.5" }),
                make_row("two", { "r1", "r3" }),
        });

        // overlaps with m1
        auto m3 = make_mutation(s2, "0", { "s1" }, {
                make_row("one", { "r1", "r3" }),
        });

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();

        destroy(std::move(m1));
        destroy(std::move(s1));
        cl.set_schema(s2);

        auto l2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout).get0();
        auto f3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout);
        BOOST_REQUIRE(!f3.available());
        destroy(std::move(l1));
        auto l3 = f3.get0();

        auto s3 = make_schema_disjoint_with_others();
        cl.set_schema(s3);

        auto m4 = make_mutation(s3, "0", { "s8", "s9"}, {
                make_row("one", { "r8", "r9" }),
                make_row("two", { "r8", "r9" }),
        });
        auto l4 = cl.lock_cells(m4.decorated_key(), partition_cells_range(m4.partition()), no_timeout).get0();
    });
}

SEASTAR_TEST_CASE(test_timed_out) {
        return seastar::async([&] {
            auto destroy = [] (auto) { };

            auto s = make_schema();
            cell_locker_stats cl_stats;
            cell_locker cl(s, cl_stats);

            auto m1 = make_mutation(s, "0", { "s1", "s2", "s3"}, {
                    make_row("one", { "r2", "r3" }),
            });
            auto m2 = make_mutation(s, "0", { }, {
                    make_row("one", { "r1", "r2" }),
            });

            auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();

            auto timeout = saturating_subtract(db::timeout_clock::now(), std::chrono::hours(1));
            BOOST_REQUIRE_THROW(cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), timeout).get0(),
                                timed_out_error);

            auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
            BOOST_REQUIRE(!f2.available());
            destroy(std::move(l1));
            auto l2 = f2.get0();
        });
}

SEASTAR_TEST_CASE(test_locker_stats) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m1 = make_mutation(s, "0", { "s2", "s3" }, {
                make_row("one", { "r1", "r2" }),
        });

        auto m2 = make_mutation(s, "0", { "s1", "s3" }, {
                make_row("one", { "r2", "r3" }),
        });

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
        BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 4);
        BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 0);

        auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
        BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 5);
        BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 1);
        BOOST_REQUIRE(!f2.available());

        destroy(std::move(l1));
        destroy(f2.get0());
        BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 8);
        BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 0);
    });
}
<commit_msg>tests/cell_locker_test: Prevent timeout underflow<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 */

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

#include "tests/test-utils.hh"

#include <seastar/core/thread.hh>

#include "cell_locking.hh"
#include "mutation.hh"
#include "schema_builder.hh"

using namespace std::literals::chrono_literals;

static schema_ptr make_schema()
{
    return schema_builder("ks", "cf")
            .with_column("pk", bytes_type, column_kind::partition_key)
            .with_column("ck", bytes_type, column_kind::clustering_key)
            .with_column("s1", bytes_type, column_kind::static_column)
            .with_column("s2", bytes_type, column_kind::static_column)
            .with_column("s3", bytes_type, column_kind::static_column)
            .with_column("r1", bytes_type)
            .with_column("r2", bytes_type)
            .with_column("r3", bytes_type)
            .build();
}

static schema_ptr make_alternative_schema()
{
    return schema_builder("ks", "cf")
            .with_column("pk", bytes_type, column_kind::partition_key)
            .with_column("ck", bytes_type, column_kind::clustering_key)
            .with_column("s0", bytes_type, column_kind::static_column)
            .with_column("s1", bytes_type, column_kind::static_column)
            .with_column("s2.5", bytes_type, column_kind::static_column)
            .with_column("s3", bytes_type, column_kind::static_column)
            .with_column("r0", bytes_type)
            .with_column("r1", bytes_type)
            .with_column("r2.5", bytes_type)
            .with_column("r3", bytes_type)
            .build();
}

static schema_ptr make_schema_disjoint_with_others()
{
    return schema_builder("ks", "cf")
            .with_column("pk", bytes_type, column_kind::partition_key)
            .with_column("ck", bytes_type, column_kind::clustering_key)
            .with_column("s8", bytes_type, column_kind::static_column)
            .with_column("s9", bytes_type, column_kind::static_column)
            .with_column("r8", bytes_type)
            .with_column("r9", bytes_type)
            .build();
}

static data_value empty_value = data_value(to_bytes(""));

static db::timeout_clock::time_point no_timeout {
    db::timeout_clock::duration(std::numeric_limits<db::timeout_clock::duration::rep>::max())
};

static auto make_row(const sstring& key, std::initializer_list<sstring> cells) {
    return std::pair<sstring, std::initializer_list<sstring>>(key, cells);
}

static mutation make_mutation(schema_ptr s, const sstring& pk, std::initializer_list<sstring> static_cells,
                              std::initializer_list<std::pair<sstring, std::initializer_list<sstring>>> clustering_cells)
{
    auto m = mutation(s, partition_key::from_single_value(*s, to_bytes(pk)));
    for (auto&& c : static_cells) {
        m.set_static_cell(to_bytes(c), empty_value, api::new_timestamp());
    }
    for (auto&& r : clustering_cells) {
        auto ck = clustering_key::from_single_value(*s, to_bytes(r.first));
        for (auto&& c : r.second) {
            m.set_clustered_cell(ck, to_bytes(c), empty_value, api::new_timestamp());
        }
    }
    return m;
}

SEASTAR_TEST_CASE(test_simple_locking_cells) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m = make_mutation(s, "0", { "s1", "s3" }, {
            make_row("one", { "r1", "r2" }),
            make_row("two", { "r2", "r3" }),
        });

        auto l1 = cl.lock_cells(m.decorated_key(), partition_cells_range(m.partition()), no_timeout).get0();
        auto f2 = cl.lock_cells(m.decorated_key(), partition_cells_range(m.partition()), no_timeout);
        BOOST_REQUIRE(!f2.available());

        destroy(std::move(l1));
        destroy(f2.get0());
    });
}

SEASTAR_TEST_CASE(test_disjoint_mutations) {
    return seastar::async([&] {
        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m1 = make_mutation(s, "0", { "s1" }, {
                make_row("one", { "r1", "r2" }),
                make_row("two", { "r3" }),
        });
        auto m2 = make_mutation(s, "0", { "s2" }, {
                make_row("two", { "r1", "r2" }),
                make_row("one", { "r3" }),
        });

        auto m3 = mutation(s, partition_key::from_single_value(*s, to_bytes("1")));
        m3.partition() = mutation_partition(*s, m1.partition());

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
        auto l2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout).get0();
        auto l3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout).get0();
    });
}

SEASTAR_TEST_CASE(test_single_cell_overlap) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m1 = make_mutation(s, "0", { "s1" }, {
                make_row("one", { "r1", "r2" }),
                make_row("two", { "r3" }),
        });
        auto m2 = make_mutation(s, "0", { "s1" }, {
                make_row("two", { "r1", "r2" }),
                make_row("one", { "r3" }),
        });
        auto m3 = make_mutation(s, "0", { "s2" }, {
                make_row("two", { "r1" }),
                make_row("one", { "r2", "r3" }),
        });

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
        auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
        BOOST_REQUIRE(!f2.available());
        destroy(std::move(l1));
        auto l2 = f2.get0();
        auto f3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout);
        BOOST_REQUIRE(!f3.available());
        destroy(std::move(l2));
        auto l3 = f3.get0();
    });
}

SEASTAR_TEST_CASE(test_schema_change) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s1 = make_schema();
        auto s2 = make_alternative_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s1, cl_stats);

        auto m1 = make_mutation(s1, "0", { "s1", "s2", "s3"}, {
            make_row("one", { "r1", "r2", "r3" }),
        });

        // disjoint with m1
        auto m2 = make_mutation(s2, "0", { "s0", "s2.5"}, {
                make_row("one", { "r0", "r2.5" }),
                make_row("two", { "r1", "r3" }),
        });

        // overlaps with m1
        auto m3 = make_mutation(s2, "0", { "s1" }, {
                make_row("one", { "r1", "r3" }),
        });

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();

        destroy(std::move(m1));
        destroy(std::move(s1));
        cl.set_schema(s2);

        auto l2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout).get0();
        auto f3 = cl.lock_cells(m3.decorated_key(), partition_cells_range(m3.partition()), no_timeout);
        BOOST_REQUIRE(!f3.available());
        destroy(std::move(l1));
        auto l3 = f3.get0();

        auto s3 = make_schema_disjoint_with_others();
        cl.set_schema(s3);

        auto m4 = make_mutation(s3, "0", { "s8", "s9"}, {
                make_row("one", { "r8", "r9" }),
                make_row("two", { "r8", "r9" }),
        });
        auto l4 = cl.lock_cells(m4.decorated_key(), partition_cells_range(m4.partition()), no_timeout).get0();
    });
}

SEASTAR_TEST_CASE(test_timed_out) {
        return seastar::async([&] {
            auto destroy = [] (auto) { };

            auto s = make_schema();
            cell_locker_stats cl_stats;
            cell_locker cl(s, cl_stats);

            auto m1 = make_mutation(s, "0", { "s1", "s2", "s3"}, {
                    make_row("one", { "r2", "r3" }),
            });
            auto m2 = make_mutation(s, "0", { }, {
                    make_row("one", { "r1", "r2" }),
            });

            auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();

            auto timeout = db::timeout_clock::now();
            forward_jump_clocks(1h);
            BOOST_REQUIRE_THROW(cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), timeout).get0(),
                                timed_out_error);

            auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
            BOOST_REQUIRE(!f2.available());
            destroy(std::move(l1));
            auto l2 = f2.get0();
        });
}

SEASTAR_TEST_CASE(test_locker_stats) {
    return seastar::async([&] {
        auto destroy = [] (auto) { };

        auto s = make_schema();
        cell_locker_stats cl_stats;
        cell_locker cl(s, cl_stats);

        auto m1 = make_mutation(s, "0", { "s2", "s3" }, {
                make_row("one", { "r1", "r2" }),
        });

        auto m2 = make_mutation(s, "0", { "s1", "s3" }, {
                make_row("one", { "r2", "r3" }),
        });

        auto l1 = cl.lock_cells(m1.decorated_key(), partition_cells_range(m1.partition()), no_timeout).get0();
        BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 4);
        BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 0);

        auto f2 = cl.lock_cells(m2.decorated_key(), partition_cells_range(m2.partition()), no_timeout);
        BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 5);
        BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 1);
        BOOST_REQUIRE(!f2.available());

        destroy(std::move(l1));
        destroy(f2.get0());
        BOOST_REQUIRE_EQUAL(cl_stats.lock_acquisitions, 8);
        BOOST_REQUIRE_EQUAL(cl_stats.operations_waiting_for_lock, 0);
    });
}
<|endoftext|>


<commit_before>#define SPICA_MLT_RENDERER_EXPORT
#include "mlt_renderer.h"

#include <algorithm>
#include <vector>
#include <stack>

namespace spica {

    namespace {

        struct PrimarySample {
            int modify_time;
            double value;
            PrimarySample() {
                modify_time = 0;
                value = rng.randReal();
            }
        };

        struct KelemenMLT {
        private:
            inline double mutate(const double x) {
                const double r = rng.randReal();
                const double s1 = 1.0 / 512.0;
                const double s2 = 1.0 / 16.0;
                const double dx = s1 / (s1 / s2 + abs(2.0 * r - 1.0)) - s1 / (s1 / s2 + 1.0);
                if (r < 0.5) {
                    const double x1 = x + dx;
                    return (x1 < 1.0) ? x1 : x1 - 1.0;
                } else {
                    const double x1 = x - dx;
                    return (x1 < 0.0) ? x1 + 1.0 : x1;
                }
            }

        public:
            int global_time;
            int large_step;
            int large_step_time;
            int used_rand_coords;

            std::vector<PrimarySample> primary_samples;
            std::stack<PrimarySample> primary_samples_stack;

            KelemenMLT() {
                global_time = large_step = large_step_time = used_rand_coords = 0;
                primary_samples.resize(128);
            }

            void initUsedRandCoords() {
                used_rand_coords = 0;
            }

            inline double nextSample() {
                if (primary_samples.size() <= used_rand_coords) {
                    primary_samples.resize(primary_samples.size() * 1.5);
                }

                if (primary_samples[used_rand_coords].modify_time < global_time) {
                    if (large_step > 0) {
                        primary_samples_stack.push(primary_samples[used_rand_coords]);
                        primary_samples[used_rand_coords].modify_time = global_time;
                        primary_samples[used_rand_coords].value = rng.randReal();
                    } else {
                        if (primary_samples[used_rand_coords].modify_time < large_step_time) {
                            primary_samples[used_rand_coords].modify_time = large_step_time;
                            primary_samples[used_rand_coords].value = rng.randReal();
                        }

                        while (primary_samples[used_rand_coords].modify_time < global_time - 1) {
                            primary_samples[used_rand_coords].value = mutate(primary_samples[used_rand_coords].value);
                            primary_samples[used_rand_coords].modify_time++;
                        }

                        primary_samples_stack.push(primary_samples[used_rand_coords]);
                        primary_samples[used_rand_coords].value = mutate(primary_samples[used_rand_coords].value);
                        primary_samples[used_rand_coords].modify_time = global_time;
                    }

                    used_rand_coords++;
                    return primary_samples[used_rand_coords - 1].value;
                }
            }
        };

        Color radiance(const Scene& scene, const Ray& ray, const int depth, KelemenMLT& mlt) {
            Intersection intersection;
            if (!scene.intersect(ray, intersection)) {
                return Color(0.0, 0.0, 0.0);
            }

            const Primitive* obj_ptr = scene.getObjectPtr(intersection.objectId());
            const HitPoint& hitpoint = intersection.hitPoint();
            const Vector3 orient_normal = hitpoint.normal().dot(ray.direction()) < 0.0 ? hitpoint.normal() : -hitpoint.normal();

            const Color& light_color = obj_ptr->color();
            double roulette_probability = std::max(light_color.red(), std::max(light_color.green(), light_color.blue()));

            if (depth > maxDepth) {
                if (mlt.nextSample() >= roulette_probability) {
                    return Color(0.0, 0.0, 0.0);
                }
            } else {
                roulette_probability = 1.0;
            }

            if (obj_ptr->reftype() == REFLECTION_DIFFUSE) {
                if (intersection.objectId() != scene.lightId()) {
                    const int shadow_ray = 1;
                    Vector3 direct_light;
                    for (int i = 0; i < shadow_ray; i++) {
                        direct_light = direct_light + direct_radiance_sample(hitpoint.position(), orient_normal, intersection.objectId(), mlt) / shadow_ray;
                    }

                    Vector3 w, u, v;
                    w = orient_normal;
                    if (abs(w.x()) > EPS) {
                        u = Vector3(0.0, 1.0, 0.0).cross(w).normalize();
                    } else {
                        u = Vector3(1.0, 0.0, 0.0).cross(w).normalize();
                    }
                    v = w.cross(u);

                    const double r1 = 2.0 * PI * mlt.nextSample();
                    const double r2 = mlt.nextSample();
                    const double r2s = sqrt(r2);
                    Vector3 next_dir = (u * cos(r1) * r2s + v * sin(r1) * r2s + w * sqrt(1.0 - r2)).normalize();

                    const Color next_bounce_color = radiance(scene, Ray(hitpoint.position(), next_dir), depth + 1, mlt);
                    return direct_light + light_color.cwiseMultiply(next_bounce_color) / roulette_probability;
                } else if (depth == 0) {
                    return obj_ptr->emission();
                } else {
                    return Color(0.0, 0.0, 0.0);
                }
            }
            else if (obj_ptr->reftype() == REFLECTION_SPECULAR) {
                Intersection light_intersect;
                Ray reflection_ray = Ray(hitpoint.position(), ray.direction() - hitpoint.normal() * 2.0 * hitpoint.normal().dot(ray.direction()));
                scene.intersect(reflection_ray, light_intersect);
                Vector3 direct_light;
                if (light_intersect.objectId() == scene.lightId()) {
                    direct_light = scene.getObjectPtr(scene.lightId())->emission();
                }
                const Color next_bounce_color = radiance(scene, reflection_ray, depth + 1, mlt);
                return direct_light + obj_ptr->color().cwiseMultiply(next_bounce_color) / roulette_probability;
            } else if (obj_ptr->reftype() == REFLECTION_REFRACTION) {
                Intersection light_intersect;
                Ray reflection_ray = Ray(hitpoint.position(), ray.direction() - hitpoint.normal() * 2.0 * hitpoint.normal().dot(ray.direction()));
                scene.intersect(reflection_ray, light_intersect);
                Vector3 direct_light;
                if (light_intersect.objectId() == scene.lightId()) {
                    direct_light = scene.getObjectPtr(scene.lightId())->emission();
                }

                bool is_incoming = hitpoint.normal().dot(orient_normal) > 0.0;

                // Snell
                const double nc = 1.0;
                const double nt = 1.5;
                const double nnt = is_incoming ? nc / nt : nt / nc;
                const double ddn = ray.direction().dot(orient_normal);
                const double cos2t = 1.0 - nnt * nnt * (1.0 - ddn * ddn);

                if (cos2t < 0.0) {
                    const Color next_bounce_color = radiance(scene, reflection_ray, depth + 1, mlt);
                    return direct_light + obj_ptr->color().cwiseMultiply(next_bounce_color) / roulette_probability;
                }

                Vector3 tdir = (ray.direction() * nnt - hitpoint.normal() * (is_incoming ? 1.0 : -1.0) * (ddn * nnt + sqrt(cos2t)));

                // Schlick
                const double a = nt - nc;
                const double b = nt + nc;
                const double R0 = (a * a) / (b * b);
                const double c = 1.0 - (is_incoming ? -ddn : tdir.dot(hitpoint.normal()));
                const double Re = R0 + (1.0 - R0) * pow(c, 5.0);
                const double Tr = 1.0 - Re;
                const double probability = 0.25 + 0.5 * Re;

                Ray refraction_ray = Ray(hitpoint.position(), tdir);
                scene.intersect(reflection_ray, light_intersect);
                Vector3 direct_light_refraction;
                if (light_intersect.objectId() == scene.lightId()) {
                    direct_light_refraction = scene.getObjectPtr(scene.lightId())->emission();
                }

                if (depth > 2) {
                    if (mlt.nextSample() < probability) {
                        const Color next_bounce_color = radiance(scene, reflection_ray, depth + 1, mlt);
                        return obj_ptr->color().cwiseMultiply(direct_light + Re * next_bounce_color) / (probability * roulette_probability);
                    } else {
                        const Color next_bounce_color = radiance(scene, refraction_ray, depth + 1, mlt);
                        return obj_ptr->color().cwiseMultiply(direct_light_refraction + Tr * next_bounce_color) / ((1.0 - probability) * roulette_probability);
                    }
                } else {
                    const Color next_bounce_color_reflect = radiance(scene, reflection_ray, depth + 1, mlt);
                    const Color next_bounce_color_refract = radiance(scene, refraction_ray, depth + 1, mlt);
                    const Color next_bounce_color = Re * next_bounce_color_reflect + Tr * next_bounce_color_refract;
                    return obj_ptr->color().cwiseMultiply(direct_light + next_bounce_color) / roulette_probability;
                }
            }
            return Color(0.0, 0.0, 0.0);
        }
    }

    MLTRenderer::MLTRenderer()
    {
    }

    MLTRenderer::~MLTRenderer()
    {
    }

    int MLTRenderer::render(const Scene& scene, const Camera& camera) {
    }

}  // namespace spica
<commit_msg>Implementing MLT.<commit_after>#define SPICA_MLT_RENDERER_EXPORT
#include "mlt_renderer.h"

#include <algorithm>
#include <vector>
#include <stack>

namespace spica {

    namespace {

        struct PrimarySample {
            int modify_time;
            double value;
            PrimarySample() {
                modify_time = 0;
                value = rng.randReal();
            }
        };

        struct KelemenMLT {
        private:
            inline double mutate(const double x) {
                const double r = rng.randReal();
                const double s1 = 1.0 / 512.0;
                const double s2 = 1.0 / 16.0;
                const double dx = s1 / (s1 / s2 + abs(2.0 * r - 1.0)) - s1 / (s1 / s2 + 1.0);
                if (r < 0.5) {
                    const double x1 = x + dx;
                    return (x1 < 1.0) ? x1 : x1 - 1.0;
                } else {
                    const double x1 = x - dx;
                    return (x1 < 0.0) ? x1 + 1.0 : x1;
                }
            }

        public:
            int global_time;
            int large_step;
            int large_step_time;
            int used_rand_coords;

            std::vector<PrimarySample> primary_samples;
            std::stack<PrimarySample> primary_samples_stack;

            KelemenMLT() {
                global_time = large_step = large_step_time = used_rand_coords = 0;
                primary_samples.resize(128);
            }

            void initUsedRandCoords() {
                used_rand_coords = 0;
            }

            inline double nextSample() {
                if (primary_samples.size() <= used_rand_coords) {
                    primary_samples.resize(primary_samples.size() * 1.5);
                }

                if (primary_samples[used_rand_coords].modify_time < global_time) {
                    if (large_step > 0) {
                        primary_samples_stack.push(primary_samples[used_rand_coords]);
                        primary_samples[used_rand_coords].modify_time = global_time;
                        primary_samples[used_rand_coords].value = rng.randReal();
                    } else {
                        if (primary_samples[used_rand_coords].modify_time < large_step_time) {
                            primary_samples[used_rand_coords].modify_time = large_step_time;
                            primary_samples[used_rand_coords].value = rng.randReal();
                        }

                        while (primary_samples[used_rand_coords].modify_time < global_time - 1) {
                            primary_samples[used_rand_coords].value = mutate(primary_samples[used_rand_coords].value);
                            primary_samples[used_rand_coords].modify_time++;
                        }

                        primary_samples_stack.push(primary_samples[used_rand_coords]);
                        primary_samples[used_rand_coords].value = mutate(primary_samples[used_rand_coords].value);
                        primary_samples[used_rand_coords].modify_time = global_time;
                    }

                    used_rand_coords++;
                    return primary_samples[used_rand_coords - 1].value;
                }
            }
        };

        Color radiance(const Scene& scene, const Ray& ray, const int depth, KelemenMLT& mlt) {
            Intersection intersection;
            if (!scene.intersect(ray, intersection)) {
                return Color(0.0, 0.0, 0.0);
            }

            const Primitive* obj_ptr = scene.getObjectPtr(intersection.objectId());
            const HitPoint& hitpoint = intersection.hitPoint();
            const Vector3 orient_normal = hitpoint.normal().dot(ray.direction()) < 0.0 ? hitpoint.normal() : -hitpoint.normal();

            const Color& light_color = obj_ptr->color();
            double roulette_probability = std::max(light_color.red(), std::max(light_color.green(), light_color.blue()));

            if (depth > maxDepth) {
                if (mlt.nextSample() >= roulette_probability) {
                    return Color(0.0, 0.0, 0.0);
                }
            } else {
                roulette_probability = 1.0;
            }

            if (obj_ptr->reftype() == REFLECTION_DIFFUSE) {
                if (intersection.objectId() != scene.lightId()) {
                    const int shadow_ray = 1;
                    Vector3 direct_light;
                    for (int i = 0; i < shadow_ray; i++) {
                        direct_light = direct_light + direct_radiance_sample(hitpoint.position(), orient_normal, intersection.objectId(), mlt) / shadow_ray;
                    }

                    Vector3 w, u, v;
                    w = orient_normal;
                    if (abs(w.x()) > EPS) {
                        u = Vector3(0.0, 1.0, 0.0).cross(w).normalize();
                    } else {
                        u = Vector3(1.0, 0.0, 0.0).cross(w).normalize();
                    }
                    v = w.cross(u);

                    const double r1 = 2.0 * PI * mlt.nextSample();
                    const double r2 = mlt.nextSample();
                    const double r2s = sqrt(r2);
                    Vector3 next_dir = (u * cos(r1) * r2s + v * sin(r1) * r2s + w * sqrt(1.0 - r2)).normalize();

                    const Color next_bounce_color = radiance(scene, Ray(hitpoint.position(), next_dir), depth + 1, mlt);
                    return direct_light + light_color.cwiseMultiply(next_bounce_color) / roulette_probability;
                } else if (depth == 0) {
                    return obj_ptr->emission();
                } else {
                    return Color(0.0, 0.0, 0.0);
                }
            }
            else if (obj_ptr->reftype() == REFLECTION_SPECULAR) {
                Intersection light_intersect;
                Ray reflection_ray = Ray(hitpoint.position(), ray.direction() - hitpoint.normal() * 2.0 * hitpoint.normal().dot(ray.direction()));
                scene.intersect(reflection_ray, light_intersect);
                Vector3 direct_light;
                if (light_intersect.objectId() == scene.lightId()) {
                    direct_light = scene.getObjectPtr(scene.lightId())->emission();
                }
                const Color next_bounce_color = radiance(scene, reflection_ray, depth + 1, mlt);
                return direct_light + obj_ptr->color().cwiseMultiply(next_bounce_color) / roulette_probability;
            } else if (obj_ptr->reftype() == REFLECTION_REFRACTION) {
                Intersection light_intersect;
                Ray reflection_ray = Ray(hitpoint.position(), ray.direction() - hitpoint.normal() * 2.0 * hitpoint.normal().dot(ray.direction()));
                scene.intersect(reflection_ray, light_intersect);
                Vector3 direct_light;
                if (light_intersect.objectId() == scene.lightId()) {
                    direct_light = scene.getObjectPtr(scene.lightId())->emission();
                }

                bool is_incoming = hitpoint.normal().dot(orient_normal) > 0.0;

                // Snell
                const double nc = 1.0;
                const double nt = 1.5;
                const double nnt = is_incoming ? nc / nt : nt / nc;
                const double ddn = ray.direction().dot(orient_normal);
                const double cos2t = 1.0 - nnt * nnt * (1.0 - ddn * ddn);

                if (cos2t < 0.0) {
                    const Color next_bounce_color = radiance(scene, reflection_ray, depth + 1, mlt);
                    return direct_light + obj_ptr->color().cwiseMultiply(next_bounce_color) / roulette_probability;
                }

                Vector3 tdir = (ray.direction() * nnt - hitpoint.normal() * (is_incoming ? 1.0 : -1.0) * (ddn * nnt + sqrt(cos2t)));

                // Schlick
                const double a = nt - nc;
                const double b = nt + nc;
                const double R0 = (a * a) / (b * b);
                const double c = 1.0 - (is_incoming ? -ddn : tdir.dot(hitpoint.normal()));
                const double Re = R0 + (1.0 - R0) * pow(c, 5.0);
                const double Tr = 1.0 - Re;
                const double probability = 0.25 + 0.5 * Re;

                Ray refraction_ray = Ray(hitpoint.position(), tdir);
                scene.intersect(reflection_ray, light_intersect);
                Vector3 direct_light_refraction;
                if (light_intersect.objectId() == scene.lightId()) {
                    direct_light_refraction = scene.getObjectPtr(scene.lightId())->emission();
                }

                if (depth > 2) {
                    if (mlt.nextSample() < probability) {
                        const Color next_bounce_color = radiance(scene, reflection_ray, depth + 1, mlt);
                        return obj_ptr->color().cwiseMultiply(direct_light + Re * next_bounce_color) / (probability * roulette_probability);
                    } else {
                        const Color next_bounce_color = radiance(scene, refraction_ray, depth + 1, mlt);
                        return obj_ptr->color().cwiseMultiply(direct_light_refraction + Tr * next_bounce_color) / ((1.0 - probability) * roulette_probability);
                    }
                } else {
                    const Color next_bounce_color_reflect = radiance(scene, reflection_ray, depth + 1, mlt);
                    const Color next_bounce_color_refract = radiance(scene, refraction_ray, depth + 1, mlt);
                    const Color next_bounce_color = Re * next_bounce_color_reflect + Tr * next_bounce_color_refract;
                    return obj_ptr->color().cwiseMultiply(direct_light + next_bounce_color) / roulette_probability;
                }
            }
            return Color(0.0, 0.0, 0.0);
        }

		struct PathSample {
			int x, y;
			Color F;
			double weight;
			PathSample(const int x_ = 0, const int y_ = 0, const Color& F_ = Color(), const double weight_ = 1.0)
				: x(x_)
				, y(y_)
				, F(F_)
				, weight(weight_)
			{
			}
		};

		PathSample generate_new_path(const Ray& camera, const Vector3& cx, const Vector3& cy, const int width, const int height, KelemenMLT& mlt, int x, int y) {
			double weight = 4.0;
			if (x < 0) {
				weight *= width;
				x = mlt.nextSample() * width;
				if (x == width) {
					x = 0;
				}
			}

			if (y < 0) {
				weight *= height;
				y = mlt.nextSample() * height;
				if (y == height) {
					y = 0;
				}
			}

			int sx = mlt.nextSample() < 0.5 ? 0 : 1;
			int sy = mlt.nextSample() < 0.5 ? 0 : 1;

			const double r1 = 2.0 * mlt.nextSample();
			const double r2 = 2.0 * mlt.nextSample();
			const double dx = r1 < 1.0 ? sqrt(r1) - 1.0 : 1.0 - sqrt(2.0 - r1);
			const double dy = r2 < 1.0 ? sqrt(r2) - 1.0 : 1.0 - sqrt(2.0 - r2);
			Vector3 dir = cx * (((sx + 0.5 + dx) / 2.0 + x) / width - 0.5) + cy * (((sy + 0.5 + dy) / 2.0 + y) / height - 0.5) + camera.direction();
			const Ray ray = Ray(camera.origin() + camera.direction() * 130.0, dir.normalize());

			Color c = radiance(scene, ray, 0, mlt);

			return PathSample(x, y, c, weight);
		}

    }  // anonymous namespace

    MLTRenderer::MLTRenderer()
    {
    }

    MLTRenderer::~MLTRenderer()
    {
    }

    int MLTRenderer::render(const Scene& scene, const Camera& camera) {
		const int width = camera.imageWidth();
		const int height = camera.imageHeight();
		const int mlt_num = width * height; // TODO: Revise
		Image image(width, height);
		for (int mi = 0; mi < mlt_num; mi++) {
			KelemenMLT mlt;

			int seed_path_max = width * height;
			if (seed_path_max <= 0) {
				seed_path_max = 1;
			}

			std::vector<PathSample> seed_paths(seed_path_max);
			double sumI = 0.0;
			mlt.large_step = 1;
			for (int i = 0; i < seed_path_max; i++) {
				mlt.initUsedRandCoords();
				PathSample smaple = generate_new_path(scene, camera.lens().normal(), cx, cy, width, height, mlt, -1, -1);
				mlt.global_time++;
				while (!mlt.primary_samples_stack.empty()) {
					mlt.primary_samples_stack.pop();
				}

				sumI += luminance(sample.F);
				seed_paths[i] = sample;
			}
		}
    }

}  // namespace spica
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* common headers */
#include "common.h"

/* interface header */
#include "WinJoystick.h"

/* implementation headers */
#include <mmsystem.h>
#include "ErrorHandler.h"
#include "TextUtils.h"

WinJoystick::WinJoystick()
{
}

WinJoystick::~WinJoystick()
{
}

void	      WinJoystick::initJoystick(const char* joystickName)
{
  inited = false;

  if (!strcmp(joystickName, "off") || !strcmp(joystickName, "")) {
    return;
  }

  if (strlen(joystickName) < 11) {
    printError("Invalid joystick name.");
    return;
  }

  if (joystickName[10] == '1')
    JoystickID = JOYSTICKID1;
  else if (joystickName[10] == '2')
    JoystickID = JOYSTICKID2;

  JOYINFO joyInfo;
  JOYCAPS joyCaps;
  if ((joyGetPos(JoystickID, &joyInfo) != JOYERR_NOERROR) ||
      (joyGetDevCaps(JoystickID, &joyCaps, sizeof(joyCaps)) != JOYERR_NOERROR)) {
    printError("Unable to initialize joystick.  Perhaps it is not plugged in?");
    return;
  }

  xMin = (float)joyCaps.wXmin;
  xMax = (float)joyCaps.wXmax;
  yMin = (float)joyCaps.wYmin;
  yMax = (float)joyCaps.wYmax;

  inited = true;
}

bool	      WinJoystick::joystick() const
{
  return inited;
}

void	      WinJoystick::getJoy(int& x, int& y) const
{
  if (!inited)
    return;

  JOYINFOEX joyInfo;
  // we're only interested in position
  joyInfo.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_USEDEADZONE;

  // check for errors
  if (joyGetPosEx(JoystickID, &joyInfo) != JOYERR_NOERROR) {
    printError("Could not get extended info from joystick");
    return;
  }

  // adjust X and Y to scale
  x = (joyInfo.dwXpos / xMax) * 2000 - 1000;
  y = (joyInfo.dwYpos / yMax) * 2000 - 1000;

  // ballistic
  x = (x * abs(x)) / 1000;
  y = (y * abs(y)) / 1000;

}

unsigned long WinJoystick::getJoyButtons() const
{
  if (!inited)
    return 0;

  // FIXME - Should use joyGetPosEx and JOYINFOEX, to get the rest of the buttons,
  // but wasn't working for me.
  JOYINFO joyInfo;

  // check for errors
  if (joyGetPos(JoystickID, &joyInfo) != JOYERR_NOERROR) {
    printError("Could not get extended info from joystick");
    return 0;
  }

  unsigned long retbuts = joyInfo.wButtons;
  unsigned long buttons = 0;
  if (retbuts & JOY_BUTTON1)  buttons = buttons | 0x00001;
  if (retbuts & JOY_BUTTON2)  buttons = buttons | 0x00002;
  if (retbuts & JOY_BUTTON3)  buttons = buttons | 0x00004;
  if (retbuts & JOY_BUTTON4)  buttons = buttons | 0x00008;
/*  if (retbuts & JOY_BUTTON5)  buttons = buttons | 0x00010;
  if (retbuts & JOY_BUTTON6)  buttons = buttons | 0x00020;
  if (retbuts & JOY_BUTTON7)  buttons = buttons | 0x00040;
  if (retbuts & JOY_BUTTON8)  buttons = buttons | 0x00080;
  if (retbuts & JOY_BUTTON9)  buttons = buttons | 0x00100;
  if (retbuts & JOY_BUTTON10) buttons = buttons | 0x00200; */

  return buttons;
}

void	      WinJoystick::getJoyDevices(std::vector<std::string> &list) const
{
  list.clear();
  if (joyGetNumDevs() != 0) {
    // we have at least one joystick driver, get the name of both joystick IDs if they exist.
    JOYCAPS joyCaps;
    if (joyGetDevCaps(JOYSTICKID1, &joyCaps, sizeof(joyCaps)) == JOYERR_NOERROR) {
      list.push_back(string_util::format("Joystick 1 (%s)", joyCaps.szOEMVxD));
    }
    if (joyGetDevCaps(JOYSTICKID2, &joyCaps, sizeof(joyCaps)) == JOYERR_NOERROR) {
      list.push_back(string_util::format("Joystick 2 (%s)", joyCaps.szOEMVxD));
    }
  }
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Make native windows MMSystem joystick use up to ten buttons<commit_after>/* bzflag
 * Copyright (c) 1993 - 2004 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* common headers */
#include "common.h"

/* interface header */
#include "WinJoystick.h"

/* implementation headers */
#include <mmsystem.h>
#include "ErrorHandler.h"
#include "TextUtils.h"

WinJoystick::WinJoystick()
{
}

WinJoystick::~WinJoystick()
{
}

void	      WinJoystick::initJoystick(const char* joystickName)
{
  inited = false;

  if (!strcmp(joystickName, "off") || !strcmp(joystickName, "")) {
    return;
  }

  if (strlen(joystickName) < 11) {
    printError("Invalid joystick name.");
    return;
  }

  if (joystickName[10] == '1')
    JoystickID = JOYSTICKID1;
  else if (joystickName[10] == '2')
    JoystickID = JOYSTICKID2;

  JOYINFO joyInfo;
  JOYCAPS joyCaps;
  if ((joyGetPos(JoystickID, &joyInfo) != JOYERR_NOERROR) ||
      (joyGetDevCaps(JoystickID, &joyCaps, sizeof(joyCaps)) != JOYERR_NOERROR)) {
    printError("Unable to initialize joystick.  Perhaps it is not plugged in?");
    return;
  }

  xMin = (float)joyCaps.wXmin;
  xMax = (float)joyCaps.wXmax;
  yMin = (float)joyCaps.wYmin;
  yMax = (float)joyCaps.wYmax;

  inited = true;
}

bool	      WinJoystick::joystick() const
{
  return inited;
}

void	      WinJoystick::getJoy(int& x, int& y) const
{
  if (!inited)
    return;

  JOYINFOEX joyInfo;
  // we're only interested in position
  joyInfo.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_USEDEADZONE;
  joyInfo.dwSize = sizeof(joyInfo);

  // check for errors
  if (joyGetPosEx(JoystickID, &joyInfo) != JOYERR_NOERROR) {
    printError("Could not get extended info from joystick");
    return;
  }

  // adjust X and Y to scale
  x = (joyInfo.dwXpos / xMax) * 2000 - 1000;
  y = (joyInfo.dwYpos / yMax) * 2000 - 1000;

  // ballistic
  x = (x * abs(x)) / 1000;
  y = (y * abs(y)) / 1000;

}

unsigned long WinJoystick::getJoyButtons() const
{
  if (!inited)
    return 0;

  JOYINFOEX joyInfo;
  // we're only interested in buttons
  joyInfo.dwFlags = JOY_RETURNBUTTONS;
  joyInfo.dwSize = sizeof(joyInfo);

  // check for errors
  if (joyGetPosEx(JoystickID, &joyInfo) != JOYERR_NOERROR) {
    printError("Could not get extended info from joystick");
    return 0;
  }

  unsigned long retbuts = joyInfo.dwButtons;
  unsigned long buttons = 0;
  if (retbuts & JOY_BUTTON1)  buttons = buttons | 0x00001;
  if (retbuts & JOY_BUTTON2)  buttons = buttons | 0x00002;
  if (retbuts & JOY_BUTTON3)  buttons = buttons | 0x00004;
  if (retbuts & JOY_BUTTON4)  buttons = buttons | 0x00008;
  if (retbuts & JOY_BUTTON5)  buttons = buttons | 0x00010;
  if (retbuts & JOY_BUTTON6)  buttons = buttons | 0x00020;
  if (retbuts & JOY_BUTTON7)  buttons = buttons | 0x00040;
  if (retbuts & JOY_BUTTON8)  buttons = buttons | 0x00080;
  if (retbuts & JOY_BUTTON9)  buttons = buttons | 0x00100;
  if (retbuts & JOY_BUTTON10) buttons = buttons | 0x00200;

  return buttons;
}

void	      WinJoystick::getJoyDevices(std::vector<std::string> &list) const
{
  list.clear();
  if (joyGetNumDevs() != 0) {
    // we have at least one joystick driver, get the name of both joystick IDs if they exist.
    JOYCAPS joyCaps;
    if (joyGetDevCaps(JOYSTICKID1, &joyCaps, sizeof(joyCaps)) == JOYERR_NOERROR) {
      list.push_back(string_util::format("Joystick 1 (%s)", joyCaps.szOEMVxD));
    }
    if (joyGetDevCaps(JOYSTICKID2, &joyCaps, sizeof(joyCaps)) == JOYERR_NOERROR) {
      list.push_back(string_util::format("Joystick 2 (%s)", joyCaps.szOEMVxD));
    }
  }
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  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
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is Jan Boelsche (regular.gonzales@googlemail.com).
//

#include "PluginManager.h"

#include "NodeDefinition.h"

#include "../base/DlfcnWrapper.h"
#include "../base/FileHelper.h"
#include "../base/Logger.h"
#include "../base/OSHelper.h"

#include <iostream>
#include <string>

using namespace std;
using namespace avg;

#ifdef _WIN32
#define PATH_DELIMITER ";"
#define PLUGIN_EXTENSION ".dll"
#else
#define PATH_DELIMITER ":"
#define PLUGIN_EXTENSION ".so"
#endif

PluginManager::PluginNotFound::PluginNotFound(const string& sMessage) :
    Exception(AVG_ERR_FILEIO, sMessage) {}

PluginManager::PluginCorrupted::PluginCorrupted(const string& sMessage) :
    Exception(AVG_ERR_CORRUPT_PLUGIN, sMessage) {}

PluginManager& PluginManager::get()
{
    static PluginManager s_Instance;
    return s_Instance;
}

PluginManager::PluginManager()
{
    setSearchPath(string("."PATH_DELIMITER) + "./plugin"PATH_DELIMITER +
            getAvgLibPath() + "plugin");
}

void PluginManager::setSearchPath(const string& sNewPath)
{
    m_sCurrentSearchPath = sNewPath;
    parsePath(m_sCurrentSearchPath);
}

string PluginManager::getSearchPath() const
{
    return m_sCurrentSearchPath;
}

boost::python::object PluginManager::loadPlugin(const std::string& sPluginName)
{
    // is it loaded aready?
    PluginMap::iterator i = m_LoadedPlugins.find(sPluginName);
    if (i == m_LoadedPlugins.end()) {
        // no, let's try to load it!
        string sFullpath = locateSharedObject(sPluginName+PLUGIN_EXTENSION);
        void *handle = internalLoadPlugin(sFullpath);
        // add to map of loaded plugins
        m_LoadedPlugins[sPluginName] = make_pair(handle, 1);
    } else {
        // yes, just increase the reference count
        int referenceCount = i->second.second;
        ++referenceCount;
        m_LoadedPlugins[sPluginName] = make_pair(i->second.first, referenceCount);
    }
    boost::python::object sysModule(boost::python::handle<>(PyImport_ImportModule("sys")));
    return sysModule.attr("modules")[sPluginName];
}

string PluginManager::locateSharedObject(const string& sFilename)
{
    vector<string>::iterator i = m_PathComponents.begin();
    string sFullpath;
    while (i != m_PathComponents.end()) {
        sFullpath = *i + sFilename;
        if (fileExists(sFullpath)) {
            return sFullpath;
        }
        ++i;
    }
    string sMessage = "Unable to locate plugin file '" + sFilename
            + "'. Was looking in " + m_sCurrentSearchPath;
    AVG_TRACE(Logger::PLUGIN, sMessage);
    throw PluginNotFound(sMessage);
}

string PluginManager::checkDirectory(const string& sDirectory)
{
    string sFixedDirectory;
    char lastChar = *sDirectory.rbegin();
    if (lastChar != '/' && lastChar != '\\') {
        sFixedDirectory = sDirectory + "/";
    } else {
        sFixedDirectory = sDirectory;
    }
    return sFixedDirectory;
}

void PluginManager::parsePath(const string& sPath)
{
    // break the string into colon separated components
    // and make sure each component has a trailing slash
    // warn about non-existing directories

    m_PathComponents.clear();
    string sRemaining = sPath;
    string::size_type i;
    do {
        i = sRemaining.find(PATH_DELIMITER);
        string sDirectory;
        if (i == string::npos) {
            sDirectory = sRemaining;
            sRemaining = "";
        } else {
            sDirectory = sRemaining.substr(0, i);
            sRemaining = sRemaining.substr(i+1);
        }
        sDirectory = checkDirectory(sDirectory);

        m_PathComponents.push_back(sDirectory);
    } while (!sRemaining.empty());
    AVG_TRACE(Logger::PLUGIN, "Plugin search path set to '" << sPath << "'");
}

void* PluginManager::internalLoadPlugin(const string& sFullpath)
{
    void *handle = dlopen(sFullpath.c_str(), RTLD_LOCAL | RTLD_NOW);
    if (!handle) {
        string sMessage(dlerror());
        AVG_TRACE(Logger::PLUGIN, "Could not load plugin. dlopen failed with message '"
                << sMessage << "'");
        throw PluginCorrupted(sMessage);
    }
    try {
        registerPlugin(handle);
    } catch(PluginCorrupted& e) {
        dlclose(handle);
        throw e;
    }
    AVG_TRACE(Logger::PLUGIN, "Loaded plugin '" << sFullpath << "'");
    return handle;
}

void PluginManager::registerPlugin(void* handle)
{
   typedef void (*RegisterPluginPtr)();
   RegisterPluginPtr registerPlugin =
       reinterpret_cast<RegisterPluginPtr>(dlsym(handle, "registerPlugin"));

    if (registerPlugin) {
        registerPlugin();
    } else {
        AVG_TRACE(Logger::PLUGIN, "No plugin registration function detected");
        throw PluginCorrupted("No plugin registration function detected");
    }
}

<commit_msg>Fixed default plugin search path on linux.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2011 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  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
//
//  Current versions can be found at www.libavg.de
//
//  Original author of this file is Jan Boelsche (regular.gonzales@googlemail.com).
//

#include "PluginManager.h"

#include "NodeDefinition.h"

#include "../base/DlfcnWrapper.h"
#include "../base/FileHelper.h"
#include "../base/Logger.h"
#include "../base/OSHelper.h"

#include <iostream>
#include <string>

using namespace std;
using namespace avg;

#ifdef _WIN32
#define PATH_DELIMITER ";"
#define PLUGIN_EXTENSION ".dll"
#else
#define PATH_DELIMITER ":"
#define PLUGIN_EXTENSION ".so"
#endif

PluginManager::PluginNotFound::PluginNotFound(const string& sMessage) :
    Exception(AVG_ERR_FILEIO, sMessage) {}

PluginManager::PluginCorrupted::PluginCorrupted(const string& sMessage) :
    Exception(AVG_ERR_CORRUPT_PLUGIN, sMessage) {}

PluginManager& PluginManager::get()
{
    static PluginManager s_Instance;
    return s_Instance;
}

PluginManager::PluginManager()
{
    setSearchPath(string("."PATH_DELIMITER) + "./plugin"PATH_DELIMITER +
            getPath(getAvgLibPath()) + "plugin");
}

void PluginManager::setSearchPath(const string& sNewPath)
{
    m_sCurrentSearchPath = sNewPath;
    parsePath(m_sCurrentSearchPath);
}

string PluginManager::getSearchPath() const
{
    return m_sCurrentSearchPath;
}

boost::python::object PluginManager::loadPlugin(const std::string& sPluginName)
{
    // is it loaded aready?
    PluginMap::iterator i = m_LoadedPlugins.find(sPluginName);
    if (i == m_LoadedPlugins.end()) {
        // no, let's try to load it!
        string sFullpath = locateSharedObject(sPluginName+PLUGIN_EXTENSION);
        void *handle = internalLoadPlugin(sFullpath);
        // add to map of loaded plugins
        m_LoadedPlugins[sPluginName] = make_pair(handle, 1);
    } else {
        // yes, just increase the reference count
        int referenceCount = i->second.second;
        ++referenceCount;
        m_LoadedPlugins[sPluginName] = make_pair(i->second.first, referenceCount);
    }
    boost::python::object sysModule(boost::python::handle<>(PyImport_ImportModule("sys")));
    return sysModule.attr("modules")[sPluginName];
}

string PluginManager::locateSharedObject(const string& sFilename)
{
    vector<string>::iterator i = m_PathComponents.begin();
    string sFullpath;
    while (i != m_PathComponents.end()) {
        sFullpath = *i + sFilename;
        if (fileExists(sFullpath)) {
            return sFullpath;
        }
        ++i;
    }
    string sMessage = "Unable to locate plugin file '" + sFilename
            + "'. Was looking in " + m_sCurrentSearchPath;
    AVG_TRACE(Logger::PLUGIN, sMessage);
    throw PluginNotFound(sMessage);
}

string PluginManager::checkDirectory(const string& sDirectory)
{
    string sFixedDirectory;
    char lastChar = *sDirectory.rbegin();
    if (lastChar != '/' && lastChar != '\\') {
        sFixedDirectory = sDirectory + "/";
    } else {
        sFixedDirectory = sDirectory;
    }
    return sFixedDirectory;
}

void PluginManager::parsePath(const string& sPath)
{
    // break the string into colon separated components
    // and make sure each component has a trailing slash
    // warn about non-existing directories

    m_PathComponents.clear();
    string sRemaining = sPath;
    string::size_type i;
    do {
        i = sRemaining.find(PATH_DELIMITER);
        string sDirectory;
        if (i == string::npos) {
            sDirectory = sRemaining;
            sRemaining = "";
        } else {
            sDirectory = sRemaining.substr(0, i);
            sRemaining = sRemaining.substr(i+1);
        }
        sDirectory = checkDirectory(sDirectory);

        m_PathComponents.push_back(sDirectory);
    } while (!sRemaining.empty());
    AVG_TRACE(Logger::PLUGIN, "Plugin search path set to '" << sPath << "'");
}

void* PluginManager::internalLoadPlugin(const string& sFullpath)
{
    void *handle = dlopen(sFullpath.c_str(), RTLD_LOCAL | RTLD_NOW);
    if (!handle) {
        string sMessage(dlerror());
        AVG_TRACE(Logger::PLUGIN, "Could not load plugin. dlopen failed with message '"
                << sMessage << "'");
        throw PluginCorrupted(sMessage);
    }
    try {
        registerPlugin(handle);
    } catch(PluginCorrupted& e) {
        dlclose(handle);
        throw e;
    }
    AVG_TRACE(Logger::PLUGIN, "Loaded plugin '" << sFullpath << "'");
    return handle;
}

void PluginManager::registerPlugin(void* handle)
{
   typedef void (*RegisterPluginPtr)();
   RegisterPluginPtr registerPlugin =
       reinterpret_cast<RegisterPluginPtr>(dlsym(handle, "registerPlugin"));

    if (registerPlugin) {
        registerPlugin();
    } else {
        AVG_TRACE(Logger::PLUGIN, "No plugin registration function detected");
        throw PluginCorrupted("No plugin registration function detected");
    }
}

<|endoftext|>


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

#include "ZipFileInput.h"

#include <zip.h>
#include "Exception.h"

namespace stromx
{
    namespace core
    {
        ZipFileInput::ZipFileInput(const std::string& archive)
          : m_archiveHandle(0),
            m_initialized(false),
            m_archive(archive),
            m_currentFile(0)
        {
            int error = 0;
            m_archiveHandle = zip_open(m_archive.c_str(), 0, &error);

            if(! m_archiveHandle)
                throw FileAccessFailed(m_archive, "Failed to open zip archive.");
        }

        ZipFileInput::~ZipFileInput()
        {
            if(m_archiveHandle)
                zip_close(m_archiveHandle);
        }

        void ZipFileInput::initialize(const std::string& text, const std::string& filename)
        {
            m_currentText.clear();
            m_currentText.str(text);

            if(m_currentFile)
            {
                delete m_currentFile;
                m_currentFile = 0;
            }

            m_currentFilename = filename;
            m_initialized = true;
        }

        const bool ZipFileInput::hasFile() const
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            return ! m_currentFilename.empty();
        }

        std::istream& ZipFileInput::text()
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            return m_currentText;
        }

        std::istream& ZipFileInput::openFile(const stromx::core::InputProvider::OpenMode mode)
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            if(m_currentFile)
                throw WrongState("File has already been opened.");

            if(! hasFile())
                throw NoInputFile();

            std::ios_base::openmode iosmode = std::ios_base::in;
            if(mode == BINARY)
                iosmode |= std::ios_base::binary;

            struct zip_stat stat;
            if(zip_stat(m_archiveHandle, m_currentFilename.c_str(), 0, &stat) < 0)
                throw FileAccessFailed(m_currentFilename, m_archive, "Failed to access file in zip archive.");

            int fileSize = stat.size;
            char* content = new char[fileSize];

            zip_file* file = zip_fopen(m_archiveHandle, m_currentFilename.c_str(), 0);
            if(! file)
                throw FileAccessFailed(m_currentFilename, m_archive, "Failed to open file in zip archive.");

            if(zip_fread(file, content, fileSize) != fileSize)
                throw FileAccessFailed(m_currentFilename, m_archive, "Failed to read file in zip archive.");

            m_currentFile = new std::istringstream(std::string(content, fileSize), iosmode);

            return *m_currentFile;
        }

        std::istream& ZipFileInput::file()
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            if(! m_currentFile)
                throw WrongState("File has not been opened.");

            return *m_currentFile;
        }
    }
}
<commit_msg>Fixed Visual studion warning<commit_after>/*
*  Copyright 2012 Matthias Fuchs
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

#include "ZipFileInput.h"

#include <zip.h>
#include "Exception.h"

namespace stromx
{
    namespace core
    {
        ZipFileInput::ZipFileInput(const std::string& archive)
          : m_archiveHandle(0),
            m_initialized(false),
            m_archive(archive),
            m_currentFile(0)
        {
            int error = 0;
            m_archiveHandle = zip_open(m_archive.c_str(), 0, &error);

            if(! m_archiveHandle)
                throw FileAccessFailed(m_archive, "Failed to open zip archive.");
        }

        ZipFileInput::~ZipFileInput()
        {
            if(m_archiveHandle)
                zip_close(m_archiveHandle);
        }

        void ZipFileInput::initialize(const std::string& text, const std::string& filename)
        {
            m_currentText.clear();
            m_currentText.str(text);

            if(m_currentFile)
            {
                delete m_currentFile;
                m_currentFile = 0;
            }

            m_currentFilename = filename;
            m_initialized = true;
        }

        const bool ZipFileInput::hasFile() const
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            return ! m_currentFilename.empty();
        }

        std::istream& ZipFileInput::text()
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            return m_currentText;
        }

        std::istream& ZipFileInput::openFile(const stromx::core::InputProvider::OpenMode mode)
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            if(m_currentFile)
                throw WrongState("File has already been opened.");

            if(! hasFile())
                throw NoInputFile();

            std::ios_base::openmode iosmode = std::ios_base::in;
            if(mode == BINARY)
                iosmode |= std::ios_base::binary;

            struct zip_stat stat;
            if(zip_stat(m_archiveHandle, m_currentFilename.c_str(), 0, &stat) < 0)
                throw FileAccessFailed(m_currentFilename, m_archive, "Failed to access file in zip archive.");

            unsigned int fileSize = (unsigned int)(stat.size);
            char* content = new char[fileSize];

            zip_file* file = zip_fopen(m_archiveHandle, m_currentFilename.c_str(), 0);
            if(! file)
                throw FileAccessFailed(m_currentFilename, m_archive, "Failed to open file in zip archive.");

            if(zip_fread(file, content, fileSize) != fileSize)
                throw FileAccessFailed(m_currentFilename, m_archive, "Failed to read file in zip archive.");

            m_currentFile = new std::istringstream(std::string(content, fileSize), iosmode);

            return *m_currentFile;
        }

        std::istream& ZipFileInput::file()
        {
            if(! m_initialized)
                throw WrongState("Zip file input has not been initialized.");

            if(! m_currentFile)
                throw WrongState("File has not been opened.");

            return *m_currentFile;
        }
    }
}
<|endoftext|>


<commit_before>/**
 * projectM-qt -- Qt4 based projectM GUI
 * Copyright (C)2003-2004 projectM Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 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
 * See 'LICENSE.txt' included within this release
 *
 */

#ifndef NULLABLE_HPP
#define NULLABLE_HPP

template <class Value>
class Nullable {
	public:
		Nullable(const Value & value) : m_value(value), m_hasValue(true) {}
		Nullable() :m_hasValue(false) {}

		Nullable & operator=(const Value & value) {
			m_value = value;
			m_hasValue = true;
		}

		void nullify() {
			m_hasValue = false;
		}

		const Value & value() const { return m_value;}
		bool hasValue() const { return m_hasValue;}
	private:
		Value m_value;
		bool m_hasValue;
};
#endif
<commit_msg>Add return value to non-void function template<commit_after>/**
 * projectM-qt -- Qt4 based projectM GUI
 * Copyright (C)2003-2004 projectM Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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 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
 * See 'LICENSE.txt' included within this release
 *
 */

#ifndef NULLABLE_HPP
#define NULLABLE_HPP

template <class Value>
class Nullable {
	public:
		Nullable(const Value & value) : m_value(value), m_hasValue(true) {}
		Nullable() :m_hasValue(false) {}

		Nullable & operator=(const Value & value) {
			m_value = value;
			m_hasValue = true;
			static Nullable tmp = 0;
			return tmp;
		}

		void nullify() {
			m_hasValue = false;
		}

		const Value & value() const { return m_value;}
		bool hasValue() const { return m_hasValue;}
	private:
		Value m_value;
		bool m_hasValue;
};
#endif
<|endoftext|>


<commit_before>/**
 * message.cpp
 *
 *  Created on: 11 окт. 2015 г.
 *      Author: zmij
 */

#include <pushkin/l10n/message.hpp>
#include <pushkin/l10n/message_io.hpp>
#include <pushkin/l10n/message_util.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <sstream>
#include <map>
#include <algorithm>

namespace psst {
namespace l10n {

::std::locale::id domain_name_facet::id;
::std::locale::id context_name_facet::id;
::std::locale::id locale_name_facet::id;

namespace detail {

format::format(localized_message const& msg)
    : fmt_{ new formatted_message{ msg } }
{
}

format::format(localized_message&& msg)
    : fmt_{ new formatted_message{ ::std::move(msg) } }
{
}

format::format(formatted_message_ptr&& fmt)
    : fmt_{ ::std::move(fmt) }
{
}

message_args::message_args(message_args const& rhs)
    : args_{}
{
    args_.reserve(rhs.args_.size());
    ::std::transform(rhs.args_.begin(), rhs.args_.end(),
        ::std::back_inserter(args_),
         [](arg_holder const& arg)
         {
            return arg->clone();
         });
}

message_args::message_args(message_args&& rhs)
    : args_{::std::move(rhs.args_)}
{
}

}  /* namespace detail */

namespace {
    const std::map< message::message_type, std::string > TYPE_TO_STRING {
        { message::message_type::empty, "" },
        { message::message_type::simple, "L10N" },
        { message::message_type::plural, "L10NN" },
        { message::message_type::context, "L10NC" },
        { message::message_type::context_plural, "L10NNC" },
    }; // TYPE_TO_STRING
    const std::map< std::string, message::message_type > STRING_TO_TYPE {
        { "L10N", message::message_type::simple },
        { "L10NN", message::message_type::plural },
        { "L10NC", message::message_type::context },
        { "L10NNC", message::message_type::context_plural },
    }; // STRING_TO_TYPE

    const ::std::string DEFAULT_DOMAIN = "";
} // namespace

// Generated output operator
std::ostream&
operator << (std::ostream& out, message::message_type val)
{
    std::ostream::sentry s (out);
    if (s) {
        auto f = TYPE_TO_STRING.find(val);
        if (f != TYPE_TO_STRING.end()) {
            out << f->second;
        } else {
            out << "Unknown type " << (int)val;
        }
    }
    return out;
}
// Generated input operator
std::istream&
operator >> (std::istream& in, message::message_type& val)
{
    std::istream::sentry s (in);
    if (!s) return in;

    std::string name;
    if (in >> name) {
        auto f = STRING_TO_TYPE.find(name);
        if (f != STRING_TO_TYPE.end()) {
            val = f->second;
        } else {
            val = message::message_type::empty;
            in.setstate(std::ios_base::failbit);
        }
    }

    return in;
}

message::message() : type_(message_type::empty), n_(0)
{
}

message::message(optional_string const& domain)
    : type_(message_type::empty), domain_(domain), n_(0)
{
}

message::message(std::string const& id, optional_string const& domain)
    : type_(message_type::simple), msgid_(id), msgstr_(id), domain_(domain), n_(0)
{
}

message::message(id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::simple), msgid_(id_n_str.first), msgstr_(id_n_str.second), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& context_str,
        std::string const& id, optional_string const& domain)
    : type_(message_type::context), msgid_(id), msgstr_(id), context_(context_str), domain_(domain), n_(0)
{
}

message::message(std::string const& context_str,
        id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::context), msgid_(id_n_str.first), msgstr_(id_n_str.second), context_(context_str), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& singular,
        std::string const& plural_str,
        int n, optional_string const& domain)
    : type_(message_type::plural), msgid_(singular), msgstr_(singular), plural_(plural_str), domain_(domain), n_(n)
{
}

message::message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        int n, optional_string const& domain)
    : type_(message_type::context_plural), msgid_(singular), msgstr_(singular), context_(context),
      plural_(plural), domain_(domain), n_(n)
{
}

void
message::swap(message& rhs) noexcept
{
    using std::swap;
    swap(type_, rhs.type_);
    swap(msgid_, rhs.msgid_);
    swap(msgstr_, rhs.msgstr_);
    swap(plural_, rhs.plural_);
    swap(context_, rhs.context_);
    swap(n_, rhs.n_);
    swap(domain_, rhs.domain_);
    swap(args_, rhs.args_);
}

::std::string const&
message::plural() const
{
    if (!plural_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't contain a plural form" };
    return *plural_;
    }

::std::string const&
message::context() const
{
    if (!context_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't have context" };
    return *context_;
    }

::std::string const&
message::domain() const
{
    if (!domain_.is_initialized())
        return DEFAULT_DOMAIN;
    return *domain_;
}

void
message::domain( std::string const& domain)
{
    domain_ = domain;
}

void
message::set_plural()
{
    switch (type_) {
        case message_type::simple:
        case message_type::plural:
            type_ = message_type::plural; break;
        case message_type::context:
        case message_type::context_plural:
            type_ = message_type::context_plural; break;
        default:
            throw ::std::runtime_error{"Cannot convert message to a plural form"};
    }

    plural_ = msgid_;
}

void
message::set_plural(int n)
{
    set_plural();
    n_ = n;
}

message::localized_message
message::translate(int n) const
{
    switch (type_) {
        case message_type::empty:
            return localized_message();
        case message_type::simple:
            return localized_message(msgid_);
        case message_type::context:
            return localized_message(context_.value(), msgid_);
        case message_type::plural:
            return localized_message(msgid_, plural_.value(), n);
        case message_type::context_plural:
            return localized_message(context_.value(), msgid_, plural_.value(), n);
        default:
            throw std::runtime_error("Unknown message type");
    }
}

detail::format
message::format(int n, bool feed_plural) const
{
    detail::format fmt{translate(n)};
    if (has_plural() && feed_plural)
        fmt % n;
    fmt % args_;
    return fmt;
}

void
message::write(std::ostream& os) const
{
    namespace locn = boost::locale;
    if (domain_.is_initialized()) {
        os << locn::as::domain(domain_.value());
    }
    if(has_format_args()) {
        os << format();
    } else {
        os << translate(n_);
    }
}

void
message::collect(message_list& messages) const
{
    for (auto const& arg : args_) {
        arg->collect(messages);
    }
}

message
message::create_message(::std::string const& id, get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& context,
            std::string const& id,
            get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{context, id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            } else {
                f(msg, nm);
            }
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

message
message::create_message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{context, singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            }
            if (ph.uses > 1)
                f(msg, nm);
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

std::ostream&
operator << (std::ostream& out, message const& val)
{
    std::ostream::sentry s(out);
    if (s) {
        val.write(out);
    }
    return out;
}

::std::istream&
operator >> (::std::istream& is, message& val)
{
    ::std::istream::sentry s(is);
    if(!s) return is;

    ::std::string msgstr;

    char c;
    while(is.get(c))
        msgstr.push_back(c);

    message::id_str_pair id_n_str{
        (val.id().empty() ? msgstr : val.id()), msgstr
    };

    message::optional_string domain;
    message::optional_string context;
    auto loc = is.getloc();
    if (::std::has_facet<domain_name_facet>(loc)) {
        domain = ::std::use_facet<domain_name_facet>(loc).domain();
    }
    if (::std::has_facet<context_name_facet>(loc)) {
        context = ::std::use_facet<context_name_facet>(loc).context();
    }

    if (context.is_initialized()) {
        val = message{*context, id_n_str, domain};
    } else {
        val = message{id_n_str, domain};
    }

    if(val.msgstr().find("{1}") != std::string::npos)
        val.set_plural();

    return is;
}

} /* namespace l10n */
} /* namespace psst */
<commit_msg>AWM-8562 format() if has_plural<commit_after>/**
 * message.cpp
 *
 *  Created on: 11 окт. 2015 г.
 *      Author: zmij
 */

#include <pushkin/l10n/message.hpp>
#include <pushkin/l10n/message_io.hpp>
#include <pushkin/l10n/message_util.hpp>

#include <boost/lexical_cast.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <sstream>
#include <map>
#include <algorithm>

namespace psst {
namespace l10n {

::std::locale::id domain_name_facet::id;
::std::locale::id context_name_facet::id;
::std::locale::id locale_name_facet::id;

namespace detail {

format::format(localized_message const& msg)
    : fmt_{ new formatted_message{ msg } }
{
}

format::format(localized_message&& msg)
    : fmt_{ new formatted_message{ ::std::move(msg) } }
{
}

format::format(formatted_message_ptr&& fmt)
    : fmt_{ ::std::move(fmt) }
{
}

message_args::message_args(message_args const& rhs)
    : args_{}
{
    args_.reserve(rhs.args_.size());
    ::std::transform(rhs.args_.begin(), rhs.args_.end(),
        ::std::back_inserter(args_),
         [](arg_holder const& arg)
         {
            return arg->clone();
         });
}

message_args::message_args(message_args&& rhs)
    : args_{::std::move(rhs.args_)}
{
}

}  /* namespace detail */

namespace {
    const std::map< message::message_type, std::string > TYPE_TO_STRING {
        { message::message_type::empty, "" },
        { message::message_type::simple, "L10N" },
        { message::message_type::plural, "L10NN" },
        { message::message_type::context, "L10NC" },
        { message::message_type::context_plural, "L10NNC" },
    }; // TYPE_TO_STRING
    const std::map< std::string, message::message_type > STRING_TO_TYPE {
        { "L10N", message::message_type::simple },
        { "L10NN", message::message_type::plural },
        { "L10NC", message::message_type::context },
        { "L10NNC", message::message_type::context_plural },
    }; // STRING_TO_TYPE

    const ::std::string DEFAULT_DOMAIN = "";
} // namespace

// Generated output operator
std::ostream&
operator << (std::ostream& out, message::message_type val)
{
    std::ostream::sentry s (out);
    if (s) {
        auto f = TYPE_TO_STRING.find(val);
        if (f != TYPE_TO_STRING.end()) {
            out << f->second;
        } else {
            out << "Unknown type " << (int)val;
        }
    }
    return out;
}
// Generated input operator
std::istream&
operator >> (std::istream& in, message::message_type& val)
{
    std::istream::sentry s (in);
    if (!s) return in;

    std::string name;
    if (in >> name) {
        auto f = STRING_TO_TYPE.find(name);
        if (f != STRING_TO_TYPE.end()) {
            val = f->second;
        } else {
            val = message::message_type::empty;
            in.setstate(std::ios_base::failbit);
        }
    }

    return in;
}

message::message() : type_(message_type::empty), n_(0)
{
}

message::message(optional_string const& domain)
    : type_(message_type::empty), domain_(domain), n_(0)
{
}

message::message(std::string const& id, optional_string const& domain)
    : type_(message_type::simple), msgid_(id), msgstr_(id), domain_(domain), n_(0)
{
}

message::message(id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::simple), msgid_(id_n_str.first), msgstr_(id_n_str.second), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& context_str,
        std::string const& id, optional_string const& domain)
    : type_(message_type::context), msgid_(id), msgstr_(id), context_(context_str), domain_(domain), n_(0)
{
}

message::message(std::string const& context_str,
        id_str_pair const& id_n_str,
        domain_type const& domain)
    : type_(message_type::context), msgid_(id_n_str.first), msgstr_(id_n_str.second), context_(context_str), domain_(domain), n_(0)
{
    if(msgstr_.find("{1}") != std::string::npos)
        set_plural();
}

message::message(std::string const& singular,
        std::string const& plural_str,
        int n, optional_string const& domain)
    : type_(message_type::plural), msgid_(singular), msgstr_(singular), plural_(plural_str), domain_(domain), n_(n)
{
}

message::message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        int n, optional_string const& domain)
    : type_(message_type::context_plural), msgid_(singular), msgstr_(singular), context_(context),
      plural_(plural), domain_(domain), n_(n)
{
}

void
message::swap(message& rhs) noexcept
{
    using std::swap;
    swap(type_, rhs.type_);
    swap(msgid_, rhs.msgid_);
    swap(msgstr_, rhs.msgstr_);
    swap(plural_, rhs.plural_);
    swap(context_, rhs.context_);
    swap(n_, rhs.n_);
    swap(domain_, rhs.domain_);
    swap(args_, rhs.args_);
}

::std::string const&
message::plural() const
{
    if (!plural_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't contain a plural form" };
    return *plural_;
    }

::std::string const&
message::context() const
{
    if (!context_.is_initialized())
        throw ::std::runtime_error{
            "Message msgid '" + msgid_ + "' doesn't have context" };
    return *context_;
    }

::std::string const&
message::domain() const
{
    if (!domain_.is_initialized())
        return DEFAULT_DOMAIN;
    return *domain_;
}

void
message::domain( std::string const& domain)
{
    domain_ = domain;
}

void
message::set_plural()
{
    switch (type_) {
        case message_type::simple:
        case message_type::plural:
            type_ = message_type::plural; break;
        case message_type::context:
        case message_type::context_plural:
            type_ = message_type::context_plural; break;
        default:
            throw ::std::runtime_error{"Cannot convert message to a plural form"};
    }

    plural_ = msgid_;
}

void
message::set_plural(int n)
{
    set_plural();
    n_ = n;
}

message::localized_message
message::translate(int n) const
{
    switch (type_) {
        case message_type::empty:
            return localized_message();
        case message_type::simple:
            return localized_message(msgid_);
        case message_type::context:
            return localized_message(context_.value(), msgid_);
        case message_type::plural:
            return localized_message(msgid_, plural_.value(), n);
        case message_type::context_plural:
            return localized_message(context_.value(), msgid_, plural_.value(), n);
        default:
            throw std::runtime_error("Unknown message type");
    }
}

detail::format
message::format(int n, bool feed_plural) const
{
    detail::format fmt{translate(n)};
    if (has_plural() && feed_plural)
        fmt % n;
    fmt % args_;
    return fmt;
}

void
message::write(std::ostream& os) const
{
    namespace locn = boost::locale;
    if (domain_.is_initialized()) {
        os << locn::as::domain(domain_.value());
    }
    if(has_plural() || has_format_args()) {
        os << format();
    } else {
        os << translate(n_);
    }
}

void
message::collect(message_list& messages) const
{
    for (auto const& arg : args_) {
        arg->collect(messages);
    }
}

message
message::create_message(::std::string const& id, get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& context,
            std::string const& id,
            get_named_param_func f,
            domain_type const& domain)
{
    auto id_phs = extract_named_placeholders(id);
    message msg{context, id_phs.first, domain};
    for (auto const& ph : id_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        f(msg, nm);
    }
    return msg;
}

message
message::create_message(std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            } else {
                f(msg, nm);
            }
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

message
message::create_message(std::string const& context,
        std::string const& singular,
        std::string const& plural,
        get_named_param_func f,
        get_n_func get_n,
        int n,
        domain_type const& domain)
{
    auto singular_phs = extract_named_placeholders(singular);
    auto plural_phs   = extract_named_placeholders(plural);
    message msg{context, singular_phs.first, plural_phs.first, n, domain};
    for (auto const& ph : singular_phs.second) {
        auto const& nm = ::boost::get<::std::string>(ph.id);
        if (ph.is_pluralizer) {
            if (get_n) {
                msg.set_n(get_n(nm));
            }
            if (ph.uses > 1)
                f(msg, nm);
        } else {
            f(msg, nm);
        }
    }
    return msg;
}

std::ostream&
operator << (std::ostream& out, message const& val)
{
    std::ostream::sentry s(out);
    if (s) {
        val.write(out);
    }
    return out;
}

::std::istream&
operator >> (::std::istream& is, message& val)
{
    ::std::istream::sentry s(is);
    if(!s) return is;

    ::std::string msgstr;

    char c;
    while(is.get(c))
        msgstr.push_back(c);

    message::id_str_pair id_n_str{
        (val.id().empty() ? msgstr : val.id()), msgstr
    };

    message::optional_string domain;
    message::optional_string context;
    auto loc = is.getloc();
    if (::std::has_facet<domain_name_facet>(loc)) {
        domain = ::std::use_facet<domain_name_facet>(loc).domain();
    }
    if (::std::has_facet<context_name_facet>(loc)) {
        context = ::std::use_facet<context_name_facet>(loc).context();
    }

    if (context.is_initialized()) {
        val = message{*context, id_n_str, domain};
    } else {
        val = message{id_n_str, domain};
    }

    if(val.msgstr().find("{1}") != std::string::npos)
        val.set_plural();

    return is;
}

} /* namespace l10n */
} /* namespace psst */
<|endoftext|>


<commit_before>// RUN: clang -shared %S/call_lib.c -olibcall_lib%shlibext
// RUN: cat %s | %cling | FileCheck %s

.L libcall_lib
extern "C" int cling_testlibrary_function();
int i = cling_testlibrary_function();
extern "C" int printf(const char* fmt, ...);
printf("got i=%d\n", i); // CHECK: got i=66
.q
<commit_msg>Try to fix intermittent test failure (library not yet built)<commit_after>// RUN: clang -shared %S/call_lib.c -olibcall_lib%shlibext && cat %s | %cling | FileCheck %s

.L libcall_lib
extern "C" int cling_testlibrary_function();
int i = cling_testlibrary_function();
extern "C" int printf(const char* fmt, ...);
printf("got i=%d\n", i); // CHECK: got i=66
.q
<|endoftext|>