<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2016 ScyllaDB
 */

#include "loopback_socket.hh"
#include "rpc/rpc.hh"
#include "rpc/lz4_compressor.hh"
#include "rpc/multi_algo_compressor_factory.hh"
#include "test-utils.hh"
#include "core/thread.hh"
#include "core/sleep.hh"

using namespace seastar;

struct serializer {
};

template <typename T, typename Output>
inline
void write_arithmetic_type(Output& out, T v) {
    static_assert(std::is_arithmetic<T>::value, "must be arithmetic type");
    return out.write(reinterpret_cast<const char*>(&v), sizeof(T));
}

template <typename T, typename Input>
inline
T read_arithmetic_type(Input& in) {
    static_assert(std::is_arithmetic<T>::value, "must be arithmetic type");
    T v;
    in.read(reinterpret_cast<char*>(&v), sizeof(T));
    return v;
}

template <typename Output>
inline void write(serializer, Output& output, int32_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, uint32_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, int64_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, uint64_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, double v) { return write_arithmetic_type(output, v); }
template <typename Input>
inline int32_t read(serializer, Input& input, rpc::type<int32_t>) { return read_arithmetic_type<int32_t>(input); }
template <typename Input>
inline uint32_t read(serializer, Input& input, rpc::type<uint32_t>) { return read_arithmetic_type<uint32_t>(input); }
template <typename Input>
inline uint64_t read(serializer, Input& input, rpc::type<uint64_t>) { return read_arithmetic_type<uint64_t>(input); }
template <typename Input>
inline uint64_t read(serializer, Input& input, rpc::type<int64_t>) { return read_arithmetic_type<int64_t>(input); }
template <typename Input>
inline double read(serializer, Input& input, rpc::type<double>) { return read_arithmetic_type<double>(input); }

template <typename Output>
inline void write(serializer, Output& out, const sstring& v) {
    write_arithmetic_type(out, uint32_t(v.size()));
    out.write(v.c_str(), v.size());
}

template <typename Input>
inline sstring read(serializer, Input& in, rpc::type<sstring>) {
    auto size = read_arithmetic_type<uint32_t>(in);
    sstring ret(sstring::initialized_later(), size);
    in.read(ret.begin(), size);
    return ret;
}

using test_rpc_proto = rpc::protocol<serializer>;
using connect_fn = std::function<test_rpc_proto::client (ipv4_addr addr)>;

class rpc_socket_impl : public ::net::socket_impl {
    promise<connected_socket> _p;
    bool _connect;
    loopback_socket_impl _socket;
public:
    rpc_socket_impl(loopback_connection_factory& factory, bool connect)
            : _connect(connect), _socket(factory) {
    }
    virtual future<connected_socket> connect(socket_address sa, socket_address local, transport proto = transport::TCP) override {
        return _connect ? _socket.connect(sa, local, proto) : _p.get_future();
    }
    virtual void shutdown() override {
        if (_connect) {
            _socket.shutdown();
        } else {
            _p.set_exception(std::make_exception_ptr(std::system_error(ECONNABORTED, std::system_category())));
        }
    }
};

future<>
with_rpc_env(rpc::resource_limits resource_limits, rpc::client_options co, rpc::server_options so, bool connect,
        std::function<future<> (test_rpc_proto& proto, test_rpc_proto::server& server, connect_fn connect)> test_fn) {
    struct state {
        test_rpc_proto proto{serializer()};
        loopback_connection_factory lcf;
        std::unique_ptr<test_rpc_proto::server> server;
    };
    return do_with(state(), [=] (state& s) {
        s.server = std::make_unique<test_rpc_proto::server>(s.proto, so, s.lcf.get_server_socket(), resource_limits);
        auto make_client = [&s, connect, co] (ipv4_addr addr) {
            auto socket = seastar::socket(std::make_unique<rpc_socket_impl>(s.lcf, connect));
            return test_rpc_proto::client(s.proto, co, std::move(socket), addr);
        };
        return test_fn(s.proto, *s.server, make_client).finally([&] {
            return s.server->stop();
        });
    });
}

struct cfactory : rpc::compressor::factory {
    mutable int use_compression = 0;
    const sstring name;
    cfactory(sstring name_ = "LZ4") : name(std::move(name_)) {}
    const sstring& supported() const override {
        return name;
    }
    std::unique_ptr<rpc::compressor> negotiate(sstring feature, bool is_server) const override {
        if (feature == name) {
            use_compression++;
            return std::make_unique<rpc::lz4_compressor>();
        } else {
            return nullptr;
        }
    }
};

SEASTAR_TEST_CASE(test_rpc_connect) {
    std::vector<future<>> fs;

    for (auto i = 0; i < 2; i++) {
        for (auto j = 0; j < 4; j++) {
            auto factory = std::make_unique<cfactory>();
            rpc::server_options so;
            rpc::client_options co;
            if (i == 1) {
                so.compressor_factory = factory.get();
            }
            if (j & 1) {
                co.compressor_factory = factory.get();
            }
            co.send_timeout_data = j & 2;
            auto f = with_rpc_env({}, co, so, true, [] (test_rpc_proto& proto, test_rpc_proto::server& s, connect_fn connect) {
                return seastar::async([&proto, connect] {
                    auto c1 = connect(ipv4_addr());
                    auto sum = proto.register_handler(1, [](int a, int b) {
                        return make_ready_future<int>(a+b);
                    });
                    auto result = sum(c1, 2, 3).get0();
                    BOOST_REQUIRE_EQUAL(result, 2 + 3);
                    c1.stop().get();
                });
            }).handle_exception([] (auto ep) {
                BOOST_FAIL("No exception expected");
            }).finally([factory = std::move(factory), i, j = j & 1] {
                if (i == 1 && j == 1) {
                    BOOST_REQUIRE_EQUAL(factory->use_compression, 2);
                } else {
                    BOOST_REQUIRE_EQUAL(factory->use_compression, 0);
                }
            });
            fs.emplace_back(std::move(f));
        }
    }
    return when_all(fs.begin(), fs.end()).discard_result();
}

SEASTAR_TEST_CASE(test_rpc_connect_multi_compression_algo) {
    auto factory1 = std::make_unique<cfactory>();
    auto factory2 = std::make_unique<cfactory>("LZ4NEW");
    rpc::server_options so;
    rpc::client_options co;
    static rpc::multi_algo_compressor_factory server({factory1.get(), factory2.get()});
    static rpc::multi_algo_compressor_factory client({factory2.get(), factory1.get()});
    so.compressor_factory = &server;
    co.compressor_factory = &client;
    return with_rpc_env({}, co, so, true, [] (test_rpc_proto& proto, test_rpc_proto::server& s, connect_fn connect) {
        return seastar::async([&proto, connect] {
            auto c1 = connect(ipv4_addr());
            auto sum = proto.register_handler(1, [](int a, int b) {
                return make_ready_future<int>(a+b);
            });
            auto result = sum(c1, 2, 3).get0();
            BOOST_REQUIRE_EQUAL(result, 2 + 3);
            c1.stop().get();
        });
    }).finally([factory1 = std::move(factory1), factory2 = std::move(factory2)] {
        BOOST_REQUIRE_EQUAL(factory1->use_compression, 0);
        BOOST_REQUIRE_EQUAL(factory2->use_compression, 2);
    });
}

SEASTAR_TEST_CASE(test_rpc_connect_abort) {
    return with_rpc_env({}, {}, {}, false, [] (test_rpc_proto& proto, test_rpc_proto::server& s, connect_fn connect) {
        return seastar::async([&proto, connect] {
            auto c1 = connect(ipv4_addr());
            auto f = proto.register_handler(1, []() { return make_ready_future<>(); });
            c1.stop().get0();
            try {
                f(c1).get0();
                BOOST_REQUIRE(false);
            } catch (...) {}
        });
    });
}

SEASTAR_TEST_CASE(test_rpc_cancel) {
    using namespace std::chrono_literals;
    return with_rpc_env({}, {}, {}, true, [] (test_rpc_proto& proto, test_rpc_proto::server& s, connect_fn connect) {
        return seastar::async([&proto, connect] {
            auto c1 = connect(ipv4_addr());
            bool rpc_executed = false;
            int good = 0;
            promise<> handler_called;
            future<> f_handler_called = handler_called.get_future();
            auto call = proto.register_handler(1, [&rpc_executed,  handler_called = std::move(handler_called)] () mutable {
                handler_called.set_value(); rpc_executed = true; return sleep(1ms);
            });
            rpc::cancellable cancel;
            auto f = call(c1, cancel);
            // cancel send side
            cancel.cancel();
            try {
                f.get();
            } catch(rpc::canceled_error&) {
                good += !rpc_executed;
            };
            f = call(c1, cancel);
            // cancel wait side
            f_handler_called.then([&cancel] {
                cancel.cancel();
            }).get();
            try {
                f.get();
            } catch(rpc::canceled_error&) {
                good += 10*rpc_executed;
            };
            c1.stop().get();
            BOOST_REQUIRE_EQUAL(good, 11);
        });
    });
}

SEASTAR_TEST_CASE(test_message_to_big) {
    return with_rpc_env({0, 1, 100}, {}, {}, true, [] (test_rpc_proto& proto, test_rpc_proto::server& s, connect_fn connect) {
        return seastar::async([&proto, connect] {
            auto c = connect(ipv4_addr());
            bool good = true;
            auto call = proto.register_handler(1, [&] (sstring payload) mutable {
                good = false;
            });
            try {
                call(c, sstring(sstring::initialized_later(), 101)).get();
                good = false;
            } catch(std::runtime_error& err) {
            } catch(...) {
                good = false;
            }
            c.stop().get();
            BOOST_REQUIRE_EQUAL(good, true);
        });
    });
}
<commit_msg>tests: rpc: add streaming tests<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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.
 */
/*
 * Copyright (C) 2016 ScyllaDB
 */

#include "loopback_socket.hh"
#include "rpc/rpc.hh"
#include "rpc/rpc_types.hh"
#include "rpc/lz4_compressor.hh"
#include "rpc/multi_algo_compressor_factory.hh"
#include "test-utils.hh"
#include "core/thread.hh"
#include "core/sleep.hh"

using namespace seastar;

struct serializer {
};

template <typename T, typename Output>
inline
void write_arithmetic_type(Output& out, T v) {
    static_assert(std::is_arithmetic<T>::value, "must be arithmetic type");
    return out.write(reinterpret_cast<const char*>(&v), sizeof(T));
}

template <typename T, typename Input>
inline
T read_arithmetic_type(Input& in) {
    static_assert(std::is_arithmetic<T>::value, "must be arithmetic type");
    T v;
    in.read(reinterpret_cast<char*>(&v), sizeof(T));
    return v;
}

template <typename Output>
inline void write(serializer, Output& output, int32_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, uint32_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, int64_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, uint64_t v) { return write_arithmetic_type(output, v); }
template <typename Output>
inline void write(serializer, Output& output, double v) { return write_arithmetic_type(output, v); }
template <typename Input>
inline int32_t read(serializer, Input& input, rpc::type<int32_t>) { return read_arithmetic_type<int32_t>(input); }
template <typename Input>
inline uint32_t read(serializer, Input& input, rpc::type<uint32_t>) { return read_arithmetic_type<uint32_t>(input); }
template <typename Input>
inline uint64_t read(serializer, Input& input, rpc::type<uint64_t>) { return read_arithmetic_type<uint64_t>(input); }
template <typename Input>
inline uint64_t read(serializer, Input& input, rpc::type<int64_t>) { return read_arithmetic_type<int64_t>(input); }
template <typename Input>
inline double read(serializer, Input& input, rpc::type<double>) { return read_arithmetic_type<double>(input); }

template <typename Output>
inline void write(serializer, Output& out, const sstring& v) {
    write_arithmetic_type(out, uint32_t(v.size()));
    out.write(v.c_str(), v.size());
}

template <typename Input>
inline sstring read(serializer, Input& in, rpc::type<sstring>) {
    auto size = read_arithmetic_type<uint32_t>(in);
    sstring ret(sstring::initialized_later(), size);
    in.read(ret.begin(), size);
    return ret;
}

using test_rpc_proto = rpc::protocol<serializer>;
using make_socket_fn = std::function<seastar::socket ()>;

struct rpc_loopback_error_injector : public loopback_error_injector {
    int _x = 0;
    bool server_rcv_error() override {
        return _x++ >= 50;
    }
};

class rpc_socket_impl : public ::net::socket_impl {
    promise<connected_socket> _p;
    bool _connect;
    loopback_socket_impl _socket;
    rpc_loopback_error_injector _error_injector;
public:
    rpc_socket_impl(loopback_connection_factory& factory, bool connect, bool inject_error)
            : _connect(connect),
              _socket(factory, inject_error ? &_error_injector : nullptr) {
    }
    virtual future<connected_socket> connect(socket_address sa, socket_address local, transport proto = transport::TCP) override {
        return _connect ? _socket.connect(sa, local, proto) : _p.get_future();
    }
    virtual void shutdown() override {
        if (_connect) {
            _socket.shutdown();
        } else {
            _p.set_exception(std::make_exception_ptr(std::system_error(ECONNABORTED, std::system_category())));
        }
    }
};

future<>
with_rpc_env(rpc::resource_limits resource_limits, rpc::server_options so, bool connect, bool inject_error,
        std::function<future<> (test_rpc_proto& proto, test_rpc_proto::server& server, make_socket_fn make_socket)> test_fn) {
    struct state {
        test_rpc_proto proto{serializer()};
        loopback_connection_factory lcf;
        std::unique_ptr<test_rpc_proto::server> server;
    };
    return do_with(state(), [=] (state& s) {
        s.server = std::make_unique<test_rpc_proto::server>(s.proto, so, s.lcf.get_server_socket(), resource_limits);
        auto make_socket = [&s, connect, inject_error] () {
            return seastar::socket(std::make_unique<rpc_socket_impl>(s.lcf, connect, inject_error));
        };
        return test_fn(s.proto, *s.server, make_socket).finally([&] {
            return s.server->stop();
        });
    });
}

struct cfactory : rpc::compressor::factory {
    mutable int use_compression = 0;
    const sstring name;
    cfactory(sstring name_ = "LZ4") : name(std::move(name_)) {}
    const sstring& supported() const override {
        return name;
    }
    std::unique_ptr<rpc::compressor> negotiate(sstring feature, bool is_server) const override {
        if (feature == name) {
            use_compression++;
            return std::make_unique<rpc::lz4_compressor>();
        } else {
            return nullptr;
        }
    }
};
#if 1
SEASTAR_TEST_CASE(test_rpc_connect) {
    std::vector<future<>> fs;

    for (auto i = 0; i < 2; i++) {
        for (auto j = 0; j < 4; j++) {
            auto factory = std::make_unique<cfactory>();
            rpc::server_options so;
            rpc::client_options co;
            if (i == 1) {
                so.compressor_factory = factory.get();
            }
            if (j & 1) {
                co.compressor_factory = factory.get();
            }
            co.send_timeout_data = j & 2;
            auto f = with_rpc_env({}, so, true, false, [co] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
                return seastar::async([&proto, make_socket, co] {
                    auto c1 = test_rpc_proto::client(proto, co, make_socket(), ipv4_addr());
                    auto sum = proto.register_handler(1, [](int a, int b) {
                        return make_ready_future<int>(a+b);
                    });
                    auto result = sum(c1, 2, 3).get0();
                    BOOST_REQUIRE_EQUAL(result, 2 + 3);
                    c1.stop().get();
                });
            }).handle_exception([] (auto ep) {
                BOOST_FAIL("No exception expected");
            }).finally([factory = std::move(factory), i, j = j & 1] {
                if (i == 1 && j == 1) {
                    BOOST_REQUIRE_EQUAL(factory->use_compression, 2);
                } else {
                    BOOST_REQUIRE_EQUAL(factory->use_compression, 0);
                }
            });
            fs.emplace_back(std::move(f));
        }
    }
    return when_all(fs.begin(), fs.end()).discard_result();
}

SEASTAR_TEST_CASE(test_rpc_connect_multi_compression_algo) {
    auto factory1 = std::make_unique<cfactory>();
    auto factory2 = std::make_unique<cfactory>("LZ4NEW");
    rpc::server_options so;
    rpc::client_options co;
    static rpc::multi_algo_compressor_factory server({factory1.get(), factory2.get()});
    static rpc::multi_algo_compressor_factory client({factory2.get(), factory1.get()});
    so.compressor_factory = &server;
    co.compressor_factory = &client;
    return with_rpc_env({}, so, true, false, [co] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
        return seastar::async([&proto, make_socket, co] {
            auto c1 = test_rpc_proto::client(proto, co, make_socket(), ipv4_addr());
            auto sum = proto.register_handler(1, [](int a, int b) {
                return make_ready_future<int>(a+b);
            });
            auto result = sum(c1, 2, 3).get0();
            BOOST_REQUIRE_EQUAL(result, 2 + 3);
            c1.stop().get();
        });
    }).finally([factory1 = std::move(factory1), factory2 = std::move(factory2)] {
        BOOST_REQUIRE_EQUAL(factory1->use_compression, 0);
        BOOST_REQUIRE_EQUAL(factory2->use_compression, 2);
    });
}

SEASTAR_TEST_CASE(test_rpc_connect_abort) {
    return with_rpc_env({}, {}, false, false, [] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
        return seastar::async([&proto, make_socket] {
            auto c1 = test_rpc_proto::client(proto, {}, make_socket(), ipv4_addr());
            auto f = proto.register_handler(1, []() { return make_ready_future<>(); });
            c1.stop().get0();
            try {
                f(c1).get0();
                BOOST_REQUIRE(false);
            } catch (...) {}
        });
    });
}

SEASTAR_TEST_CASE(test_rpc_cancel) {
    using namespace std::chrono_literals;
    return with_rpc_env({}, {}, true, false, [] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
        return seastar::async([&proto, make_socket] {
            auto c1 = test_rpc_proto::client(proto, {}, make_socket(), ipv4_addr());
            bool rpc_executed = false;
            int good = 0;
            promise<> handler_called;
            future<> f_handler_called = handler_called.get_future();
            auto call = proto.register_handler(1, [&rpc_executed,  handler_called = std::move(handler_called)] () mutable {
                handler_called.set_value(); rpc_executed = true; return sleep(1ms);
            });
            rpc::cancellable cancel;
            auto f = call(c1, cancel);
            // cancel send side
            cancel.cancel();
            try {
                f.get();
            } catch(rpc::canceled_error&) {
                good += !rpc_executed;
            };
            f = call(c1, cancel);
            // cancel wait side
            f_handler_called.then([&cancel] {
                cancel.cancel();
            }).get();
            try {
                f.get();
            } catch(rpc::canceled_error&) {
                good += 10*rpc_executed;
            };
            c1.stop().get();
            BOOST_REQUIRE_EQUAL(good, 11);
        });
    });
}

SEASTAR_TEST_CASE(test_message_to_big) {
    return with_rpc_env({0, 1, 100}, {}, true, false, [] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
        return seastar::async([&proto, make_socket] {
            auto c = test_rpc_proto::client(proto, {}, make_socket(), ipv4_addr());
            bool good = true;
            auto call = proto.register_handler(1, [&] (sstring payload) mutable {
                good = false;
            });
            try {
                call(c, sstring(sstring::initialized_later(), 101)).get();
                good = false;
            } catch(std::runtime_error& err) {
            } catch(...) {
                good = false;
            }
            c.stop().get();
            BOOST_REQUIRE_EQUAL(good, true);
        });
    });
}
#endif

struct stream_test_result {
    bool client_source_closed = false;
    bool server_source_closed = false;
    bool sink_exception = false;
    bool sink_close_exception = false;
    bool source_done_exception = false;
    bool server_done_exception = false;
    bool client_stop_exception = false;
    int server_sum = 0;
};

future<stream_test_result> stream_test_func(test_rpc_proto& proto, make_socket_fn make_socket, bool stop_client) {
    return seastar::async([&proto, make_socket, stop_client] {
        stream_test_result r;
        auto c = test_rpc_proto::client(proto, {}, make_socket(), ipv4_addr());
        future<> server_done = make_ready_future();
        proto.register_handler(1, [&](int i, rpc::source<int> source) {
            BOOST_REQUIRE_EQUAL(i, 666);
            auto sink = source.make_sink<serializer, sstring>();
            auto sink_loop = seastar::async([sink] () mutable {
                for (auto i = 0; i < 100; i++) {
                    sink("seastar").get();
                    sleep(std::chrono::milliseconds(1)).get();
                }
                sink.close().get();
            });
            auto source_loop = seastar::async([source, &r] () mutable {
                while (!r.server_source_closed) {
                    auto data = source().get0();
                    if (data) {
                        r.server_sum += std::get<0>(*data);
                    } else {
                        r.server_source_closed = true;
                    }
                }
            });
            server_done = when_all_succeed(std::move(sink_loop), std::move(source_loop)).discard_result();
            return sink;
        });
        auto call = proto.make_client<rpc::source<sstring> (int, rpc::sink<int>)>(1);
        auto x = [&] {
            try {
                return c.make_stream_sink<serializer, int>(make_socket()).get0();
            } catch (...) {
                c.stop().get();
                throw;
            }
        };
        auto sink = x();
        auto source = call(c, 666, sink).get0();
        auto source_done = seastar::async([&] {
            while (!r.client_source_closed) {
                auto data = source().get0();
                if (data) {
                    BOOST_REQUIRE_EQUAL(std::get<0>(*data), "seastar");
                } else {
                    r.client_source_closed = true;
                }
            }
        });
        auto check_exception = [] (auto f) {
            try {
                f.get();
            } catch (...) {
                return true;
            }
            return false;
        };
        future<> stop_client_future = make_ready_future();
        for (int i = 1; i < 101; i++) {
            if (stop_client && i == 50) {
                // stop client while stream is in use
                stop_client_future = c.stop();
            }
            sleep(std::chrono::milliseconds(1)).get();
            r.sink_exception = check_exception(sink(i));
            if (r.sink_exception) {
                break;
            }
        }
        r.sink_close_exception = check_exception(sink.close());
        r.source_done_exception = check_exception(std::move(source_done));
        r.server_done_exception = check_exception(std::move(server_done));
        r.client_stop_exception = check_exception(!stop_client ? c.stop() : std::move(stop_client_future));
        return r;
    });
}

SEASTAR_TEST_CASE(test_stream_simple) {
    rpc::server_options so;
    so.streaming_domain = rpc::streaming_domain_type(1);
    return with_rpc_env({}, so, true, false, [] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
        return stream_test_func(proto, make_socket, false).then([] (stream_test_result r) {
            BOOST_REQUIRE(r.client_source_closed &&
                    r.server_source_closed &&
                    r.server_sum == 5050 &&
                    !r.sink_exception &&
                    !r.sink_close_exception &&
                    !r.source_done_exception &&
                    !r.server_done_exception &&
                    !r.client_stop_exception);
        });
    });
}

SEASTAR_TEST_CASE(test_stream_stop_client) {
    rpc::server_options so;
    so.streaming_domain = rpc::streaming_domain_type(1);
    return with_rpc_env({}, so, true, false, [] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
        return stream_test_func(proto, make_socket, true).then([] (stream_test_result r) {
            BOOST_REQUIRE(!r.client_source_closed &&
                    !r.server_source_closed &&
                    r.sink_exception &&
                    r.sink_close_exception &&
                    r.source_done_exception &&
                    r.server_done_exception &&
                    !r.client_stop_exception);
        });
    });
}

SEASTAR_TEST_CASE(test_stream_connection_error) {
    rpc::server_options so;
    so.streaming_domain = rpc::streaming_domain_type(1);
    return with_rpc_env({}, so, true, true, [] (test_rpc_proto& proto, test_rpc_proto::server& s, make_socket_fn make_socket) {
        return stream_test_func(proto, make_socket, false).then([] (stream_test_result r) {
            BOOST_REQUIRE(!r.client_source_closed &&
                    !r.server_source_closed &&
                    r.sink_exception &&
                    r.sink_close_exception &&
                    r.source_done_exception &&
                    r.server_done_exception &&
                    !r.client_stop_exception);
        });
    });
}
<|endoftext|>


<commit_before>/**
 * File    : D2.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-7-15 16:51:34
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 1000000007;
const ll MOD = 1000000007;

typedef tuple<ll, ll> P;

int N;
ll H[110];

long long power(long long x, long long n)
{
  if (n == 0)
  {
    return 1;
  }
  else if (n % 2 == 1)
  {
    return (x * power(x, n - 1)) % MOD;
  }
  else
  {
    long long half = power(x, n / 2);
    return (half * half) % MOD;
  }
}

int h_ind(int l, int r)
{
  int ind = -1;
  ll mini = infty;
  for (auto i = l; i < r; i++)
  {
    if (H[i] < mini)
    {
      ind = i;
      mini = H[i];
    }
  }
  return ind;
}

P func(int l, int r, ll h)
{
  if (l == r)
  {
    return P(1, 1);
  }
  int ind = h_ind(l, r);
  ll height = H[ind] - h;
  if (l + 1 == r && height == 1)
  {
    return P(2, 1);
  }
  if (height == 1)
  {
    auto it1 = func(l, ind, h);
    auto it2 = func(ind + 1, r, h);
    ll f1 = get<0>(it1);
    ll g1 = get<1>(it1);
    ll f2 = get<0>(it2);
    ll g2 = get<1>(it2);
    ll f = (((2 * f1) % MOD) * f2) % MOD;
    ll g = (g1 * g2) % MOD;
    return P(f, g);
  }
  auto it1 = func(l, ind, h + height - 1);
  ll f1 = get<0>(it1);
  ll g1 = get<1>(it1);
  ll f = f1;
  f += 2 * (MOD - g1);
  f %= MOD;
  f += (power(2, height) * g1) % MOD;
  f %= MOD;
  ll g = (power(2, height - 1) * g1) % MOD;
  return P(f, g);
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> H[i];
  }
  cout << get<0>(func(0, N, 0)) << endl;
}<commit_msg>tried D2.cpp to 'D'<commit_after>/**
 * File    : D2.cpp
 * Author  : Kazune Takahashi
 * Created : 2018-7-15 16:51:34
 * Powered by Visual Studio Code
 */

#include <iostream>
#include <iomanip>   // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set>
#include <functional>
#include <random> // auto rd = bind(uniform_int_distribution<int>(0, 9), mt19937(19920725));
#include <chrono> // std::chrono::system_clock::time_point start_time, end_time;
// start = std::chrono::system_clock::now();
// double elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end_time-start_time).count();
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
const ll infty = 1000000007;
const ll MOD = 1000000007;

typedef tuple<ll, ll> P;

int N;
ll H[110];

long long power(long long x, long long n)
{
  if (n == 0)
  {
    return 1;
  }
  else if (n % 2 == 1)
  {
    return (x * power(x, n - 1)) % MOD;
  }
  else
  {
    long long half = power(x, n / 2);
    return (half * half) % MOD;
  }
}

int h_ind(int l, int r)
{
  int ind = -1;
  ll mini = infty;
  for (auto i = l; i < r; i++)
  {
    if (H[i] < mini)
    {
      ind = i;
      mini = H[i];
    }
  }
  return ind;
}

P func(int l, int r, ll h)
{
  if (l == r)
  {
    cerr << "func(" << l << ", " << r << ", " << h << ") = ";
    cerr << "1, 1" << endl;
    return P(1, 1);
  }
  int ind = h_ind(l, r);
  ll height = H[ind] - h;
  if (l + 1 == r && height == 1)
  {
    cerr << "func(" << l << ", " << r << ", " << h << ") = ";
    cerr << "2, 1" << endl;
    return P(2, 1);
  }
  if (height == 1)
  {
    auto it1 = func(l, ind, h);
    auto it2 = func(ind + 1, r, h);
    ll f1 = get<0>(it1);
    ll g1 = get<1>(it1);
    ll f2 = get<0>(it2);
    ll g2 = get<1>(it2);
    ll f = (((2 * f1) % MOD) * f2) % MOD;
    ll g = (g1 * g2) % MOD;
    cerr << "func(" << l << ", " << r << ", " << h << ") = ";
    cerr << f << ", " << g << endl;
    return P(f, g);
  }
  auto it1 = func(l, ind, h + height - 1);
  ll f1 = get<0>(it1);
  ll g1 = get<1>(it1);
  ll f = f1;
  f += 2 * (MOD - g1);
  f %= MOD;
  f += (power(2, height) * g1) % MOD;
  f %= MOD;
  ll g = (power(2, height - 1) * g1) % MOD;
  cerr << "func(" << l << ", " << r << ", " << h << ") = ";
  cerr << f << ", " << g << endl;
  return P(f, g);
}

int main()
{
  cin >> N;
  for (auto i = 0; i < N; i++)
  {
    cin >> H[i];
  }
  cout << get<0>(func(0, N, 0)) << endl;
}<|endoftext|>


<commit_before>// This file is a part of the OpenSurgSim project.
// Copyright 2012-2013, SimQuest Solutions Inc.
//
// 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.

/// \file
/// Tests for the View class.

#include "SurgSim/Graphics/UnitTests/MockObjects.h"

#include "gtest/gtest.h"

#include <random>

using SurgSim::Graphics::Camera;
using SurgSim::Graphics::View;

TEST(ViewTests, InitTest)
{
	ASSERT_NO_THROW({std::shared_ptr<View> view = std::make_shared<MockView>("test name");});
}

TEST(ViewTests, NameTest)
{
	std::shared_ptr<View> view = std::make_shared<MockView>("test name");

	EXPECT_EQ("test name", view->getName());
}

TEST(ViewTests, PositionAndDimensionsTest)
{
	std::shared_ptr<View> view = std::make_shared<MockView>("test name");

	std::default_random_engine generator;
	std::uniform_int_distribution<int> distribution(0, 1000);

	int x = distribution(generator);
	int y = distribution(generator);
	int width = distribution(generator);
	int height = distribution(generator);

	/// Set position and check that it set correctly
	EXPECT_TRUE(view->setPosition(x, y));

	int testX, testY;
	view->getPosition(&testX, &testY);

	EXPECT_EQ(x, testX);
	EXPECT_EQ(y, testY);

	/// Set dimensions and check that it set correctly
	EXPECT_TRUE(view->setDimensions(width, height));

	int testWidth, testHeight;
	view->getDimensions(&testWidth, &testHeight);

	EXPECT_EQ(width, testWidth);
	EXPECT_EQ(height, testHeight);
}

TEST(ViewTests, CameraTest)
{
	std::shared_ptr<View> view = std::make_shared<MockView>("test name");

	std::shared_ptr<Camera> camera = std::make_shared<MockCamera>("test camera");

	/// Set the camera and check that it set correctly
	view->setCamera(camera);

	EXPECT_EQ(camera, view->getCamera());
}

TEST(ViewTests, UpdateTest)
{
	std::shared_ptr<MockView> mockView = std::make_shared<MockView>("test name");
	std::shared_ptr<View> view = mockView;

	EXPECT_EQ(0, mockView->getNumUpdates());
	EXPECT_EQ(0.0, mockView->getSumDt());

	double sumDt = 0.0;
	std::default_random_engine generator;
	std::uniform_real_distribution<double> distribution(0.0, 1.0);

	/// Do 10 updates with random dt and check each time that the number of updates and sum of dt are correct.
	for (int i = 1; i <= 10; ++i)
	{
		double dt = distribution(generator);
		sumDt += dt;

		view->update(dt);
		EXPECT_EQ(i, mockView->getNumUpdates());
		EXPECT_LT(fabs(sumDt - mockView->getSumDt()), Eigen::NumTraits<double>::dummy_precision());
	}
}
<commit_msg>Check that setCamera() returns true in Graphics ViewTests.<commit_after>// This file is a part of the OpenSurgSim project.
// Copyright 2012-2013, SimQuest Solutions Inc.
//
// 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.

/// \file
/// Tests for the View class.

#include "SurgSim/Graphics/UnitTests/MockObjects.h"

#include "gtest/gtest.h"

#include <random>

using SurgSim::Graphics::Camera;
using SurgSim::Graphics::View;

TEST(ViewTests, InitTest)
{
	ASSERT_NO_THROW({std::shared_ptr<View> view = std::make_shared<MockView>("test name");});
}

TEST(ViewTests, NameTest)
{
	std::shared_ptr<View> view = std::make_shared<MockView>("test name");

	EXPECT_EQ("test name", view->getName());
}

TEST(ViewTests, PositionAndDimensionsTest)
{
	std::shared_ptr<View> view = std::make_shared<MockView>("test name");

	std::default_random_engine generator;
	std::uniform_int_distribution<int> distribution(0, 1000);

	int x = distribution(generator);
	int y = distribution(generator);
	int width = distribution(generator);
	int height = distribution(generator);

	/// Set position and check that it set correctly
	EXPECT_TRUE(view->setPosition(x, y));

	int testX, testY;
	view->getPosition(&testX, &testY);

	EXPECT_EQ(x, testX);
	EXPECT_EQ(y, testY);

	/// Set dimensions and check that it set correctly
	EXPECT_TRUE(view->setDimensions(width, height));

	int testWidth, testHeight;
	view->getDimensions(&testWidth, &testHeight);

	EXPECT_EQ(width, testWidth);
	EXPECT_EQ(height, testHeight);
}

TEST(ViewTests, CameraTest)
{
	std::shared_ptr<View> view = std::make_shared<MockView>("test name");

	std::shared_ptr<Camera> camera = std::make_shared<MockCamera>("test camera");

	/// Set the camera and check that it set correctly
	EXPECT_TRUE(view->setCamera(camera));

	EXPECT_EQ(camera, view->getCamera());
}

TEST(ViewTests, UpdateTest)
{
	std::shared_ptr<MockView> mockView = std::make_shared<MockView>("test name");
	std::shared_ptr<View> view = mockView;

	EXPECT_EQ(0, mockView->getNumUpdates());
	EXPECT_EQ(0.0, mockView->getSumDt());

	double sumDt = 0.0;
	std::default_random_engine generator;
	std::uniform_real_distribution<double> distribution(0.0, 1.0);

	/// Do 10 updates with random dt and check each time that the number of updates and sum of dt are correct.
	for (int i = 1; i <= 10; ++i)
	{
		double dt = distribution(generator);
		sumDt += dt;

		view->update(dt);
		EXPECT_EQ(i, mockView->getNumUpdates());
		EXPECT_LT(fabs(sumDt - mockView->getSumDt()), Eigen::NumTraits<double>::dummy_precision());
	}
}
<|endoftext|>


<commit_before>#include "Menu_button.h"
#include "Input_handler.h"

Menu_button::Menu_button(const Loader_params* params, void(*callback)()) : SDL_Game_object(params), m_callback(callback) {
	m_current_frame = MOUSE_OUT;
}

void Menu_button::draw() {
	SDL_Game_object::draw();
}

void Menu_button::update() {
	Vec2D* mouse_pos = The_Input_handler->get_mouse_position();
	double mx = mouse_pos->get_x();
	double my = mouse_pos->get_y();
	double x = m_position.get_x();
	double y = m_position.get_y();

	m_current_frame = MOUSE_OUT;

	if (mx < (x + m_width) && mx >= x && my < (y + m_height) && my >= y) {
		m_current_frame = MOUSE_OVER;
		if (The_Input_handler->get_mouse_button_state(LEFT)) {
			m_current_frame = CLICKED;
		}
	}
}

void Menu_button::clean() {
	SDL_Game_object::clean();
}<commit_msg>working button callback functionality<commit_after>#include "Menu_button.h"
#include "Input_handler.h"

Menu_button::Menu_button(const Loader_params* params, void(*callback)()) : SDL_Game_object(params), m_callback(callback) {
	m_current_frame = MOUSE_OUT;
}

void Menu_button::draw() {
	SDL_Game_object::draw();
}

void Menu_button::update() {
	Vec2D* mouse_pos = The_Input_handler->get_mouse_position();
	double mx = mouse_pos->get_x();
	double my = mouse_pos->get_y();
	double x = m_position.get_x();
	double y = m_position.get_y();

	if (mx < (x + m_width) && mx >= x && my < (y + m_height) && my >= y) {
		if (The_Input_handler->get_mouse_button_state(LEFT) && m_released) {
			m_current_frame = CLICKED;
			m_callback();
			m_released = false;
		} else if (!The_Input_handler->get_mouse_button_state(LEFT)) {
			m_released = true;
			m_current_frame = MOUSE_OVER;
		}
	} else {
		m_current_frame = MOUSE_OUT;
	}
}

void Menu_button::clean() {
	SDL_Game_object::clean();
}<|endoftext|>


<commit_before>#pragma once

#include "../utils/type_traits.hpp"

namespace autocxxpy
{
    template <class T, class T2>
    auto append_as_tuple(T&& v1, T2&& v2)
    {
        return std::make_tuple<T, remove_cvref_t<T2>>(std::move(v1), std::move(v2));
    }

    template <class ... Ts, class T2, size_t ... idx>
    auto append_as_tuple_impl(std::tuple<Ts...> tv, T2&& v2, std::index_sequence<idx...>)
    {
        return std::make_tuple<Ts ..., T2>(std::move(std::get<idx>(tv)) ..., std::move(v2));
    }

    template <class ... Ts, class T2>
    auto append_as_tuple(std::tuple<Ts ...>&& tv, T2&& v2)
    {
        return append_as_tuple_impl(std::move(tv), std::move(v2), std::index_sequence_for<Ts...>{});
    }
}
<commit_msg>Delete utils.hpp<commit_after><|endoftext|>


<commit_before>#include <string.h>
#include <thin3d/thin3d.h>

#include "base/logging.h"
#include "image/zim_load.h"
#include "image/png_load.h"
#include "file/vfs.h"
#include "ext/jpge/jpgd.h"

static const char * const glsl_fsTexCol =
"varying vec4 oColor0;\n"
"varying vec2 oTexCoord0;\n"
"uniform sampler2D Sampler0;\n"
"void main() { gl_FragColor = oColor0 * texture2D(Sampler0, oTexCoord0); }\n";

static const char * const hlslFsTexCol =
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"sampler2D Sampler0 : register(s0);\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
"  return input.color * tex2D(Sampler0, input.uv);\n"
"}\n";

static const char * const glsl_fsCol =
"varying vec4 oColor0;\n"
"void main() { gl_FragColor = oColor0; }\n";

static const char * const hlslFsCol =
"struct PS_INPUT { float4 color : COLOR0; };\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
"  return input.color;\n"
"}\n";

static const char * const glsl_vsCol =
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"varying vec4 oColor0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
"  gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
"  oColor0 = Color0;\n"
"}";

static const char * const hlslVsCol =
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float4 Color0 : COLOR0; };\n"
"float4x4 WorldViewProj;\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
"  VS_OUTPUT output;\n"
"  output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
"  output.Color0 = input.Color0;\n"
"  return output;\n"
"}\n";

static const char * const glsl_vsTexCol =
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"attribute vec2 TexCoord0;\n"
"varying vec4 oColor0;\n"
"varying vec2 oTexCoord0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
"  gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
"  oColor0 = Color0;\n"
"  oTexCoord0 = TexCoord0;\n"
"}\n";

static const char * const hlslVsTexCol =
"struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"float4x4 WorldViewProj;\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
"  VS_OUTPUT output;\n"
"  output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
"  output.Texcoord0 = input.Texcoord0;\n"
"  output.Color0 = input.Color0;\n"
"  return output;\n"
"}\n";

void Thin3DContext::CreatePresets() {
	// Build prebuilt objects
	T3DBlendStateDesc off = { false };
	T3DBlendStateDesc additive = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
	T3DBlendStateDesc standard_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::SRC_ALPHA, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
	T3DBlendStateDesc premul_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };

	bsPresets_[BS_OFF] = CreateBlendState(off);
	bsPresets_[BS_ADDITIVE] = CreateBlendState(additive);
	bsPresets_[BS_STANDARD_ALPHA] = CreateBlendState(standard_alpha);
	bsPresets_[BS_PREMUL_ALPHA] = CreateBlendState(premul_alpha);

	vsPresets_[VS_TEXTURE_COLOR_2D] = CreateVertexShader(glsl_vsTexCol, hlslVsTexCol);
	vsPresets_[VS_COLOR_2D] = CreateVertexShader(glsl_vsCol, hlslVsCol);

	fsPresets_[FS_TEXTURE_COLOR_2D] = CreateFragmentShader(glsl_fsTexCol, hlslFsTexCol);
	fsPresets_[FS_COLOR_2D] = CreateFragmentShader(glsl_fsCol, hlslFsCol);

	ssPresets_[SS_TEXTURE_COLOR_2D] = CreateShaderSet(vsPresets_[VS_TEXTURE_COLOR_2D], fsPresets_[FS_TEXTURE_COLOR_2D]);
	ssPresets_[SS_COLOR_2D] = CreateShaderSet(vsPresets_[VS_COLOR_2D], fsPresets_[FS_COLOR_2D]);
}

Thin3DContext::~Thin3DContext() {
	for (int i = 0; i < VS_MAX_PRESET; i++) {
		if (vsPresets_[i]) {
			vsPresets_[i]->Release();
		}
	}
	for (int i = 0; i < FS_MAX_PRESET; i++) {
		if (fsPresets_[i]) {
			fsPresets_[i]->Release();
		}
	}
	for (int i = 0; i < BS_MAX_PRESET; i++) {
		if (bsPresets_[i]) {
			bsPresets_[i]->Release();
		}
	}
	for (int i = 0; i < SS_MAX_PRESET; i++) {
		if (ssPresets_[i]) {
			ssPresets_[i]->Release();
		}
	}
}

static T3DImageFormat ZimToT3DFormat(int zim) {
	switch (zim) {
	case ZIM_ETC1: return T3DImageFormat::ETC1;
	case ZIM_RGBA8888: return T3DImageFormat::RGBA8888;
	case ZIM_LUMINANCE: return T3DImageFormat::LUMINANCE;
	default: return T3DImageFormat::RGBA8888;
	}
}

static T3DImageType DetectImageFileType(const uint8_t *data, size_t size) {
	if (!memcmp(data, "ZIMG", 4)) {
		return ZIM;
	} else if (!memcmp(data, "\x89\x50\x4E\x47", 4)) {
		return PNG;
	} else if (!memcmp(data, "\xff\xd8\xff\xe0", 4)) {
		return JPEG;
	} else {
		return TYPE_UNKNOWN;
	}
}

static bool LoadTextureLevels(const uint8_t *data, size_t size, T3DImageType type, int width[16], int height[16], int *num_levels, T3DImageFormat *fmt, uint8_t *image[16], int *zim_flags) {
	if (type == DETECT) {
		type = DetectImageFileType(data, size);
	}
	if (type == TYPE_UNKNOWN) {
		ELOG("File has unknown format");
		return false;
	}

	*num_levels = 0;
	*zim_flags = 0;

	switch (type) {
	case ZIM:
	{
		*num_levels = LoadZIMPtr((const uint8_t *)data, size, width, height, zim_flags, image);
		*fmt = ZimToT3DFormat(*zim_flags & ZIM_FORMAT_MASK);
	}
		break;

	case PNG:
		if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0], false)) {
			*num_levels = 1;
			*fmt = RGBA8888;
		}
		break;

	case JPEG:
		{
			int actual_components = 0;
			unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(data, (int)size, &width[0], &height[0], &actual_components, 4);
			if (jpegBuf) {
				*num_levels = 1;
				*fmt = RGBA8888;
				image[0] = (uint8_t *)jpegBuf;
			}
		}
		break;

	default:
		ELOG("Unknown image format");
		return false;
	}

	return *num_levels > 0;
}

bool Thin3DTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, T3DImageType type) {
	int width[16], height[16];
	uint8_t *image[16] = { nullptr };

	int num_levels;
	int zim_flags;
	T3DImageFormat fmt;

	if (!LoadTextureLevels(data, dataSize, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
		return false;
	}

	Create(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
	for (int i = 0; i < num_levels; i++) {
		if (image[i]) {
			SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
			free(image[i]);
		} else {
			ELOG("Missing image level %i", i);
		}
	}

	Finalize(zim_flags);
	return true;
}

bool Thin3DTexture::LoadFromFile(const std::string &filename, T3DImageType type) {
	filename_ = "";
	size_t fileSize;
	uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
	if (!buffer) {
		return false;
	}
	bool retval = LoadFromFileData(buffer, fileSize, type);
	if (retval) {
		filename_ = filename;
	} else {
		ELOG("%s: Failed to load texture %s", __FUNCTION__, filename.c_str());
	}
	delete[] buffer;
	return retval;
}

Thin3DTexture *Thin3DContext::CreateTextureFromFile(const char *filename, T3DImageType type) {
	Thin3DTexture *tex = CreateTexture();
	if (!tex->LoadFromFile(filename, type)) {
		tex->Release();
		return NULL;
	}
	return tex;
}

// TODO: Remove the code duplication between this and LoadFromFileData
Thin3DTexture *Thin3DContext::CreateTextureFromFileData(const uint8_t *data, int size, T3DImageType type) {
	int width[16], height[16];
	int num_levels = 0;
	int zim_flags = 0;
	T3DImageFormat fmt;
	uint8_t *image[16] = { nullptr };

	if (!LoadTextureLevels(data, size, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
		return NULL;
	}

	Thin3DTexture *tex = CreateTexture(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
	for (int i = 0; i < num_levels; i++) {
		tex->SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
		free(image[i]);
	}

	tex->Finalize(zim_flags);
	return tex;
}
<commit_msg>Thin3d preset GLSL shaders: Make them identical to the old GL-only shaders by adding precision qualifiers<commit_after>#include <string.h>
#include <thin3d/thin3d.h>

#include "base/logging.h"
#include "image/zim_load.h"
#include "image/png_load.h"
#include "file/vfs.h"
#include "ext/jpge/jpgd.h"

static const char * const glsl_fsTexCol =
"#ifdef GL_ES\n"
"precision lowp float;\n"
"#endif\n"
"varying vec4 oColor0;\n"
"varying vec2 oTexCoord0;\n"
"uniform sampler2D Sampler0;\n"
"void main() { gl_FragColor = texture2D(Sampler0, oTexCoord0) * oColor0; }\n";

static const char * const hlslFsTexCol =
"struct PS_INPUT { float4 color : COLOR0; float2 uv : TEXCOORD0; };\n"
"sampler2D Sampler0 : register(s0);\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
"  return input.color * tex2D(Sampler0, input.uv);\n"
"}\n";

static const char * const glsl_fsCol =
"#ifdef GL_ES\n"
"precision lowp float;\n"
"#endif\n"
"varying vec4 oColor0;\n"
"void main() { gl_FragColor = oColor0; }\n";

static const char * const hlslFsCol =
"struct PS_INPUT { float4 color : COLOR0; };\n"
"float4 main(PS_INPUT input) : COLOR0 {\n"
"  return input.color;\n"
"}\n";

static const char * const glsl_vsCol =
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"varying vec4 oColor0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
"  gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
"  oColor0 = Color0;\n"
"}";

static const char * const hlslVsCol =
"struct VS_INPUT { float3 Position : POSITION; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float4 Color0 : COLOR0; };\n"
"float4x4 WorldViewProj;\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
"  VS_OUTPUT output;\n"
"  output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
"  output.Color0 = input.Color0;\n"
"  return output;\n"
"}\n";

static const char * const glsl_vsTexCol =
"attribute vec3 Position;\n"
"attribute vec4 Color0;\n"
"attribute vec2 TexCoord0;\n"
"varying vec4 oColor0;\n"
"varying vec2 oTexCoord0;\n"
"uniform mat4 WorldViewProj;\n"
"void main() {\n"
"  gl_Position = WorldViewProj * vec4(Position, 1.0);\n"
"  oColor0 = Color0;\n"
"  oTexCoord0 = TexCoord0;\n"
"}\n";

static const char * const hlslVsTexCol =
"struct VS_INPUT { float3 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"struct VS_OUTPUT { float4 Position : POSITION; float2 Texcoord0 : TEXCOORD0; float4 Color0 : COLOR0; };\n"
"float4x4 WorldViewProj;\n"
"VS_OUTPUT main(VS_INPUT input) {\n"
"  VS_OUTPUT output;\n"
"  output.Position = mul(float4(input.Position, 1.0), WorldViewProj);\n"
"  output.Texcoord0 = input.Texcoord0;\n"
"  output.Color0 = input.Color0;\n"
"  return output;\n"
"}\n";

void Thin3DContext::CreatePresets() {
	// Build prebuilt objects
	T3DBlendStateDesc off = { false };
	T3DBlendStateDesc additive = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
	T3DBlendStateDesc standard_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::SRC_ALPHA, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };
	T3DBlendStateDesc premul_alpha = { true, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ONE_MINUS_SRC_ALPHA, T3DBlendEquation::ADD, T3DBlendFactor::ONE, T3DBlendFactor::ZERO };

	bsPresets_[BS_OFF] = CreateBlendState(off);
	bsPresets_[BS_ADDITIVE] = CreateBlendState(additive);
	bsPresets_[BS_STANDARD_ALPHA] = CreateBlendState(standard_alpha);
	bsPresets_[BS_PREMUL_ALPHA] = CreateBlendState(premul_alpha);

	vsPresets_[VS_TEXTURE_COLOR_2D] = CreateVertexShader(glsl_vsTexCol, hlslVsTexCol);
	vsPresets_[VS_COLOR_2D] = CreateVertexShader(glsl_vsCol, hlslVsCol);

	fsPresets_[FS_TEXTURE_COLOR_2D] = CreateFragmentShader(glsl_fsTexCol, hlslFsTexCol);
	fsPresets_[FS_COLOR_2D] = CreateFragmentShader(glsl_fsCol, hlslFsCol);

	ssPresets_[SS_TEXTURE_COLOR_2D] = CreateShaderSet(vsPresets_[VS_TEXTURE_COLOR_2D], fsPresets_[FS_TEXTURE_COLOR_2D]);
	ssPresets_[SS_COLOR_2D] = CreateShaderSet(vsPresets_[VS_COLOR_2D], fsPresets_[FS_COLOR_2D]);
}

Thin3DContext::~Thin3DContext() {
	for (int i = 0; i < VS_MAX_PRESET; i++) {
		if (vsPresets_[i]) {
			vsPresets_[i]->Release();
		}
	}
	for (int i = 0; i < FS_MAX_PRESET; i++) {
		if (fsPresets_[i]) {
			fsPresets_[i]->Release();
		}
	}
	for (int i = 0; i < BS_MAX_PRESET; i++) {
		if (bsPresets_[i]) {
			bsPresets_[i]->Release();
		}
	}
	for (int i = 0; i < SS_MAX_PRESET; i++) {
		if (ssPresets_[i]) {
			ssPresets_[i]->Release();
		}
	}
}

static T3DImageFormat ZimToT3DFormat(int zim) {
	switch (zim) {
	case ZIM_ETC1: return T3DImageFormat::ETC1;
	case ZIM_RGBA8888: return T3DImageFormat::RGBA8888;
	case ZIM_LUMINANCE: return T3DImageFormat::LUMINANCE;
	default: return T3DImageFormat::RGBA8888;
	}
}

static T3DImageType DetectImageFileType(const uint8_t *data, size_t size) {
	if (!memcmp(data, "ZIMG", 4)) {
		return ZIM;
	} else if (!memcmp(data, "\x89\x50\x4E\x47", 4)) {
		return PNG;
	} else if (!memcmp(data, "\xff\xd8\xff\xe0", 4)) {
		return JPEG;
	} else {
		return TYPE_UNKNOWN;
	}
}

static bool LoadTextureLevels(const uint8_t *data, size_t size, T3DImageType type, int width[16], int height[16], int *num_levels, T3DImageFormat *fmt, uint8_t *image[16], int *zim_flags) {
	if (type == DETECT) {
		type = DetectImageFileType(data, size);
	}
	if (type == TYPE_UNKNOWN) {
		ELOG("File has unknown format");
		return false;
	}

	*num_levels = 0;
	*zim_flags = 0;

	switch (type) {
	case ZIM:
	{
		*num_levels = LoadZIMPtr((const uint8_t *)data, size, width, height, zim_flags, image);
		*fmt = ZimToT3DFormat(*zim_flags & ZIM_FORMAT_MASK);
	}
		break;

	case PNG:
		if (1 == pngLoadPtr((const unsigned char *)data, size, &width[0], &height[0], &image[0], false)) {
			*num_levels = 1;
			*fmt = RGBA8888;
		}
		break;

	case JPEG:
		{
			int actual_components = 0;
			unsigned char *jpegBuf = jpgd::decompress_jpeg_image_from_memory(data, (int)size, &width[0], &height[0], &actual_components, 4);
			if (jpegBuf) {
				*num_levels = 1;
				*fmt = RGBA8888;
				image[0] = (uint8_t *)jpegBuf;
			}
		}
		break;

	default:
		ELOG("Unknown image format");
		return false;
	}

	return *num_levels > 0;
}

bool Thin3DTexture::LoadFromFileData(const uint8_t *data, size_t dataSize, T3DImageType type) {
	int width[16], height[16];
	uint8_t *image[16] = { nullptr };

	int num_levels;
	int zim_flags;
	T3DImageFormat fmt;

	if (!LoadTextureLevels(data, dataSize, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
		return false;
	}

	Create(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
	for (int i = 0; i < num_levels; i++) {
		if (image[i]) {
			SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
			free(image[i]);
		} else {
			ELOG("Missing image level %i", i);
		}
	}

	Finalize(zim_flags);
	return true;
}

bool Thin3DTexture::LoadFromFile(const std::string &filename, T3DImageType type) {
	filename_ = "";
	size_t fileSize;
	uint8_t *buffer = VFSReadFile(filename.c_str(), &fileSize);
	if (!buffer) {
		return false;
	}
	bool retval = LoadFromFileData(buffer, fileSize, type);
	if (retval) {
		filename_ = filename;
	} else {
		ELOG("%s: Failed to load texture %s", __FUNCTION__, filename.c_str());
	}
	delete[] buffer;
	return retval;
}

Thin3DTexture *Thin3DContext::CreateTextureFromFile(const char *filename, T3DImageType type) {
	Thin3DTexture *tex = CreateTexture();
	if (!tex->LoadFromFile(filename, type)) {
		tex->Release();
		return NULL;
	}
	return tex;
}

// TODO: Remove the code duplication between this and LoadFromFileData
Thin3DTexture *Thin3DContext::CreateTextureFromFileData(const uint8_t *data, int size, T3DImageType type) {
	int width[16], height[16];
	int num_levels = 0;
	int zim_flags = 0;
	T3DImageFormat fmt;
	uint8_t *image[16] = { nullptr };

	if (!LoadTextureLevels(data, size, type, width, height, &num_levels, &fmt, image, &zim_flags)) {
		return NULL;
	}

	Thin3DTexture *tex = CreateTexture(LINEAR2D, fmt, width[0], height[0], 1, num_levels);
	for (int i = 0; i < num_levels; i++) {
		tex->SetImageData(0, 0, 0, width[i], height[i], 1, i, width[i] * 4, image[i]);
		free(image[i]);
	}

	tex->Finalize(zim_flags);
	return tex;
}
<|endoftext|>


<commit_before>// @(#)root/pyroot:$Id$
// Author: Wim Lavrijsen, Apr 2004

// Bindings
#include "PyROOT.h"
#include "ConstructorHolder.h"
#include "Executors.h"
#include "ObjectProxy.h"
#include "MemoryRegulator.h"
#include "Adapters.h"

// ROOT
#include "TClass.h"
#include "TMethod.h"

// Standard
#include <string>

//- protected members --------------------------------------------------------
template< class T, class M >
Bool_t PyROOT::TConstructorHolder< T, M >::InitExecutor_( TExecutor*& executor )
{
// pick up special case new object executor
   executor = (gExecFactories[ "__init__" ])();
   return kTRUE;
}

//- constructors -------------------------------------------------------------
template< class T, class M >
PyROOT::TConstructorHolder< T, M >::TConstructorHolder( const T& klass, const M& method ) :
      TMethodHolder< T, M >( klass, method )
{
}

//____________________________________________________________________________
namespace PyROOT {

template<>
TConstructorHolder< TScopeAdapter, TMemberAdapter >::TConstructorHolder( const TScopeAdapter& klass ) :
   TMethodHolder< TScopeAdapter, TMemberAdapter >( klass, (TFunction*)0 )
{
}

} // namespace PyROOT

//- public members -----------------------------------------------------------
template< class T, class M >
PyObject* PyROOT::TConstructorHolder< T, M >::GetDocString()
{
// GetMethod() may return an empty function if this is just a special case place holder
   std::string clName = this->GetClass().Name();
   return PyROOT_PyUnicode_FromFormat( "%s::%s%s",
      clName.c_str(), clName.c_str(), this->GetMethod() ? this->GetSignatureString().c_str() : "()" );
}

//____________________________________________________________________________
template< class T, class M >
PyObject* PyROOT::TConstructorHolder< T, M >::operator()(
      ObjectProxy* self, PyObject* args, PyObject* kwds, Long_t user )
{
// preliminary check in case keywords are accidently used (they are ignored otherwise)
   if ( kwds != 0 && PyDict_Size( kwds ) ) {
      PyErr_SetString( PyExc_TypeError, "keyword arguments are not yet supported" );
      return 0;
   }

// do not allow instantiation of abstract classes
   if ( this->GetClass().IsAbstract() ) {
      PyErr_Format( PyExc_TypeError,
         "%s is abstract and can not be instantiated", this->GetClass().Name().c_str() );
      return 0;
   }

// setup as necessary
   if ( ! this->Initialize() )
      return 0;                              // important: 0, not Py_None

// fetch self, verify, and put the arguments in usable order
   if ( ! ( args = this->FilterArgs( self, args, kwds ) ) )
      return 0;

// translate the arguments
   if ( ! this->SetMethodArgs( args, user ) ) {
      Py_DECREF( args );
      return 0;
   }

   TClass* klass = (TClass*)this->GetClass().Id();

// perform the call (fails for loaded macro's)
   Long_t address = (Long_t)this->Execute( klass );

// done with filtered args
   Py_DECREF( args );

// return object if successful, lament if not
   if ( address != 0 ) {
      Py_INCREF( self );

   // note: constructors are no longer set to take ownership by default; instead that is
   // decided by the method proxy (which carries a creator flag) upon return
      self->Set( (void*)address );

   // allow lookup upon destruction on the ROOT/CINT side for TObjects
      TObject* object = (TObject*) klass->DynamicCast( TObject::Class(), (void*)address );
      if ( object )
         TMemoryRegulator::RegisterObject( self, object );

   // done with self
      Py_DECREF( self );

      Py_INCREF( Py_None );
      return Py_None;                        // by definition
   }

   if ( ! PyErr_Occurred() )   // should be set, otherwise write a generic error msg
      PyErr_SetString( PyExc_TypeError, const_cast< char* >(
         ( std::string( klass->GetName() ) + " constructor failed" ).c_str() ) );

// do not throw an exception, '0' might trigger the overload handler to choose a
// different constructor, which if all fails will throw an exception
   return 0;
}

//____________________________________________________________________________
template class PyROOT::TConstructorHolder< PyROOT::TScopeAdapter, PyROOT::TMemberAdapter >;
<commit_msg>change in who allocates memory for newly constructed objects<commit_after>// @(#)root/pyroot:$Id$
// Author: Wim Lavrijsen, Apr 2004

// Bindings
#include "PyROOT.h"
#include "ConstructorHolder.h"
#include "Executors.h"
#include "ObjectProxy.h"
#include "MemoryRegulator.h"
#include "Adapters.h"

// ROOT
#include "TClass.h"
#include "TMethod.h"

// Standard
#include <string>

//- protected members --------------------------------------------------------
template< class T, class M >
Bool_t PyROOT::TConstructorHolder< T, M >::InitExecutor_( TExecutor*& executor )
{
// pick up special case new object executor
   executor = (gExecFactories[ "__init__" ])();
   return kTRUE;
}

//- constructors -------------------------------------------------------------
template< class T, class M >
PyROOT::TConstructorHolder< T, M >::TConstructorHolder( const T& klass, const M& method ) :
      TMethodHolder< T, M >( klass, method )
{
}

//____________________________________________________________________________
namespace PyROOT {

template<>
TConstructorHolder< TScopeAdapter, TMemberAdapter >::TConstructorHolder( const TScopeAdapter& klass ) :
   TMethodHolder< TScopeAdapter, TMemberAdapter >( klass, (TFunction*)0 )
{
}

} // namespace PyROOT

//- public members -----------------------------------------------------------
template< class T, class M >
PyObject* PyROOT::TConstructorHolder< T, M >::GetDocString()
{
// GetMethod() may return an empty function if this is just a special case place holder
   std::string clName = this->GetClass().Name();
   return PyROOT_PyUnicode_FromFormat( "%s::%s%s",
      clName.c_str(), clName.c_str(), this->GetMethod() ? this->GetSignatureString().c_str() : "()" );
}

//____________________________________________________________________________
template< class T, class M >
PyObject* PyROOT::TConstructorHolder< T, M >::operator()(
      ObjectProxy* self, PyObject* args, PyObject* kwds, Long_t user )
{
// preliminary check in case keywords are accidently used (they are ignored otherwise)
   if ( kwds != 0 && PyDict_Size( kwds ) ) {
      PyErr_SetString( PyExc_TypeError, "keyword arguments are not yet supported" );
      return 0;
   }

// do not allow instantiation of abstract classes
   if ( this->GetClass().IsAbstract() ) {
      PyErr_Format( PyExc_TypeError,
         "%s is abstract and can not be instantiated", this->GetClass().Name().c_str() );
      return 0;
   }

// setup as necessary
   if ( ! this->Initialize() )
      return 0;                              // important: 0, not Py_None

// fetch self, verify, and put the arguments in usable order
   if ( ! ( args = this->FilterArgs( self, args, kwds ) ) )
      return 0;

// translate the arguments
   if ( ! this->SetMethodArgs( args, user ) ) {
      Py_DECREF( args );
      return 0;
   }

   TClass* klass = (TClass*)this->GetClass().Id();

// perform the call, 0 makes the other side allocate the memory
   Long_t address = (Long_t)this->Execute( 0 );

// done with filtered args
   Py_DECREF( args );

// return object if successful, lament if not
   if ( address != 0 ) {
      Py_INCREF( self );

   // note: constructors are no longer set to take ownership by default; instead that is
   // decided by the method proxy (which carries a creator flag) upon return
      self->Set( (void*)address );

   // allow lookup upon destruction on the ROOT/CINT side for TObjects
      TObject* object = (TObject*) klass->DynamicCast( TObject::Class(), (void*)address );
      if ( object )
         TMemoryRegulator::RegisterObject( self, object );

   // done with self
      Py_DECREF( self );

      Py_INCREF( Py_None );
      return Py_None;                        // by definition
   }

   if ( ! PyErr_Occurred() )   // should be set, otherwise write a generic error msg
      PyErr_SetString( PyExc_TypeError, const_cast< char* >(
         ( std::string( klass->GetName() ) + " constructor failed" ).c_str() ) );

// do not throw an exception, '0' might trigger the overload handler to choose a
// different constructor, which if all fails will throw an exception
   return 0;
}

//____________________________________________________________________________
template class PyROOT::TConstructorHolder< PyROOT::TScopeAdapter, PyROOT::TMemberAdapter >;
<|endoftext|>


<commit_before>//
// Copyright (c) 2009, Zbigniew Zagorski
// This software licensed under terms described in LICENSE.txt
//

#include "option.h"

#include "tinfra/tstring.h"
#include "tinfra/trace.h"

#include <ostream>
#include <cstdlib>

namespace tinfra {

//
// option_base
//

const char option_base::NO_SWITCH = 0;

option_base::option_base()
{
    option_registry::get().add(this);
}

option_base::option_base(option_list& ol)
{
    ol.add(this);
}

option_base::~option_base()
{
}

//
// option_impl
//

option_impl::option_impl(option_list& ol,char switch_letter, std::string const& name, std::string const& synopsis):
    option_base(ol),
    switch_letter(switch_letter),
    name(name),
    synopsis(synopsis)
{
}

option_impl::option_impl(option_list& ol,std::string const& name, std::string const& synopsis):
    option_base(ol),
    switch_letter(NO_SWITCH),
    name(name),
    synopsis(synopsis)
{
}

option_impl::option_impl(char switch_letter, std::string const& name, std::string const& synopsis):
    switch_letter(switch_letter),
    name(name),
    synopsis(synopsis)
{
}

option_impl::option_impl(std::string const& name, std::string const& synopsis):
    switch_letter(NO_SWITCH),
    name(name),
    synopsis(synopsis)
{
}

char option_impl::get_switch_letter() const
{
    return switch_letter;
}
std::string option_impl::get_name() const
{
    return name;
}

std::string option_impl::get_synopsis() const
{
    return synopsis;
}

//
// option_switch
//

void option_switch::accept(tstring const& input)
{
    if( input.size() == 0 ) {
        this->value_ = !default_value();
    } else if( input == "yes" ||
               input == "y" ||
               input == "1") {
        this->value_ = true;
    } else {
        this->value_ = false;
    }
    accepted_ = true;
}
//
// option_list
//

void option_list::add(option_base* opt)
{
    options.push_back(opt);
}

void remove_params(std::vector<tstring>& from_where, unsigned pos, unsigned how_many = 1)
{
    assert(pos + how_many <= from_where.size());

    std::vector<tstring>::iterator remove_begin = from_where.begin()+pos;
    std::vector<tstring>::iterator remove_end   = from_where.begin()+pos + how_many;
    from_where.erase(remove_begin, remove_end);
}

void option_list::parse(std::vector<tstring>& params)
{
    unsigned i = 0;
    while( i < params.size()) {
        tstring current = params[i];
        if( current.size() < 2 ) {
            i+=1;
            continue;
        }

        tstring option_name;
        tstring option_value;
        bool argument_present;
        option_base* opt;
        if( std::strncmp(current.data(), "--", 2) == 0 )  {
            if( current.size() == 2 ) {
                remove_params(params,i,1);
                // -- is an end of parameters
                break;
            }

            // parse only long style, gnu-like options (--foo-bar, --foo-bar=AAA, --foo-bar AAA)
            current = current.substr(2);

            size_t eq_pos = current.find_first_of('=');
            argument_present = (eq_pos != tstring::npos);
            if( argument_present ) {
                // and option=argument pair
                option_name  = current.substr(0,eq_pos);
                option_value = current.substr(eq_pos+1);
            } else {
                // only option, no argument
                option_name = current;
            }
            opt = find_by_name(option_name);
        } else if( current[0] == '-' ) {
            // parse short options:
            // -I
            // -Iparam
            // -I param
            const char shortcut = current[1];

            option_value = current.substr(2);
            argument_present = (option_value.size() != 0);
            opt = find_by_shortcut(shortcut);
	} else {
            i+=1;
            continue;
        }

        int arguments_eaten = 1;

        if( opt == 0 ) {
            // ignore unknown option
            // TODO, invent other strategy for unknown options
            i+=1;
            continue;
        }

        if( opt->needs_argument() ) {
            if( !argument_present ) {
                if( i == params.size() - 1 ) {
                    // we need argument but are at last element, so
                    // throw!
                    assert(false);
                    throw;
                }
                option_value = params[i+1];
                arguments_eaten += 1;
            }

            opt->accept(option_value);
        } else {
            if( argument_present )
                opt->accept(option_value);
            else
                opt->accept("");
        }
        remove_params(params, i, arguments_eaten);
    }
}

void option_list::print_help(tinfra::output_stream& out)
{
    std::ostringstream tmp;
    for(option_list_t::const_iterator i = options.begin(); i != options.end(); ++i)
    {
        const option_base* opt = *i;
        tmp << "    ";

        // TODO:
        // switch_letter is not yet supported so don't show it to user
        /*
        const char switch_letter =  opt->get_switch_letter();
        if( switch_letter != option_base::NO_SWITCH )
            out << "-" << switch_letter << ", ";
        */

        tmp  << "--" << opt->get_name();
        if( opt->needs_argument() ) {
            tmp  << " ARG";
        }

        tmp << "\t" << opt->get_synopsis() << "\n";
    }
    out.write(tmp.str());
}
option_base* option_list::find_by_name(tstring const& name)
{
    for(option_list_t::const_iterator i = options.begin(); i != options.end(); ++i)
    {
        option_base* opt = *i;

        if( name == opt->get_name() )
            return opt;

        // TODO: add - and _ insensitive search
    }
    return 0;
}

option_base* option_list::find_by_shortcut(char shortcut)
{
    for(option_list_t::const_iterator i = options.begin(); i != options.end(); ++i)
    {
        option_base* opt = *i;

        if( shortcut == opt->get_switch_letter() )
            return opt;
    }
    return 0;
}

option_list::option_list_t option_list::get_options()
{
    return options;
}

//
// option_registry
//
static option_list* default_option_list = 0;
static void delete_default_option_list()
{
    delete default_option_list;
}

option_list& option_registry::get()
{
    if( default_option_list == 0 ) {
        default_option_list = new option_list();
        std::atexit(delete_default_option_list);
    }
    return *default_option_list;
}

} // end namespace tinfra

// jedit: :tabSize=8:indentSize=4:noTabs=true:mode=c++:

<commit_msg>option_list::print_help(): show also short versions of options<commit_after>//
// Copyright (c) 2009, Zbigniew Zagorski
// This software licensed under terms described in LICENSE.txt
//

#include "option.h"

#include "tinfra/tstring.h"
#include "tinfra/trace.h"

#include <cstdlib>

namespace tinfra {

//
// option_base
//

const char option_base::NO_SWITCH = 0;

option_base::option_base()
{
    option_registry::get().add(this);
}

option_base::option_base(option_list& ol)
{
    ol.add(this);
}

option_base::~option_base()
{
}

//
// option_impl
//

option_impl::option_impl(option_list& ol,char switch_letter, std::string const& name, std::string const& synopsis):
    option_base(ol),
    switch_letter(switch_letter),
    name(name),
    synopsis(synopsis)
{
}

option_impl::option_impl(option_list& ol,std::string const& name, std::string const& synopsis):
    option_base(ol),
    switch_letter(NO_SWITCH),
    name(name),
    synopsis(synopsis)
{
}

option_impl::option_impl(char switch_letter, std::string const& name, std::string const& synopsis):
    switch_letter(switch_letter),
    name(name),
    synopsis(synopsis)
{
}

option_impl::option_impl(std::string const& name, std::string const& synopsis):
    switch_letter(NO_SWITCH),
    name(name),
    synopsis(synopsis)
{
}

char option_impl::get_switch_letter() const
{
    return switch_letter;
}
std::string option_impl::get_name() const
{
    return name;
}

std::string option_impl::get_synopsis() const
{
    return synopsis;
}

//
// option_switch
//

void option_switch::accept(tstring const& input)
{
    if( input.size() == 0 ) {
        this->value_ = !default_value();
    } else if( input == "yes" ||
               input == "y" ||
               input == "1") {
        this->value_ = true;
    } else {
        this->value_ = false;
    }
    accepted_ = true;
}
//
// option_list
//

void option_list::add(option_base* opt)
{
    options.push_back(opt);
}

void remove_params(std::vector<tstring>& from_where, unsigned pos, unsigned how_many = 1)
{
    assert(pos + how_many <= from_where.size());

    std::vector<tstring>::iterator remove_begin = from_where.begin()+pos;
    std::vector<tstring>::iterator remove_end   = from_where.begin()+pos + how_many;
    from_where.erase(remove_begin, remove_end);
}

void option_list::parse(std::vector<tstring>& params)
{
    unsigned i = 0;
    while( i < params.size()) {
        tstring current = params[i];
        if( current.size() < 2 ) {
            i+=1;
            continue;
        }

        tstring option_name;
        tstring option_value;
        bool argument_present;
        option_base* opt;
        if( std::strncmp(current.data(), "--", 2) == 0 )  {
            if( current.size() == 2 ) {
                remove_params(params,i,1);
                // -- is an end of parameters
                break;
            }

            // parse only long style, gnu-like options (--foo-bar, --foo-bar=AAA, --foo-bar AAA)
            current = current.substr(2);

            size_t eq_pos = current.find_first_of('=');
            argument_present = (eq_pos != tstring::npos);
            if( argument_present ) {
                // and option=argument pair
                option_name  = current.substr(0,eq_pos);
                option_value = current.substr(eq_pos+1);
            } else {
                // only option, no argument
                option_name = current;
            }
            opt = find_by_name(option_name);
        } else if( current[0] == '-' ) {
            // parse short options:
            // -I
            // -Iparam
            // -I param
            const char shortcut = current[1];

            option_value = current.substr(2);
            argument_present = (option_value.size() != 0);
            opt = find_by_shortcut(shortcut);
	} else {
            i+=1;
            continue;
        }

        int arguments_eaten = 1;

        if( opt == 0 ) {
            // ignore unknown option
            // TODO, invent other strategy for unknown options
            i+=1;
            continue;
        }

        if( opt->needs_argument() ) {
            if( !argument_present ) {
                if( i == params.size() - 1 ) {
                    // we need argument but are at last element, so
                    // throw!
                    assert(false);
                    throw;
                }
                option_value = params[i+1];
                arguments_eaten += 1;
            }

            opt->accept(option_value);
        } else {
            if( argument_present )
                opt->accept(option_value);
            else
                opt->accept("");
        }
        remove_params(params, i, arguments_eaten);
    }
}

void option_list::print_help(tinfra::output_stream& out)
{
    std::ostringstream tmp;
    for(option_list_t::const_iterator i = options.begin(); i != options.end(); ++i)
    {
        const option_base* opt = *i;
        tmp << "    ";

        const char switch_letter =  opt->get_switch_letter();
        if( switch_letter != option_base::NO_SWITCH )
            tmp << "-" << switch_letter << ", ";

        tmp  << "--" << opt->get_name();
        if( opt->needs_argument() ) {
            tmp  << " ARG";
        }

        tmp << "\t" << opt->get_synopsis() << "\n";
    }
    out.write(tmp.str());
}
option_base* option_list::find_by_name(tstring const& name)
{
    for(option_list_t::const_iterator i = options.begin(); i != options.end(); ++i)
    {
        option_base* opt = *i;

        if( name == opt->get_name() )
            return opt;

        // TODO: add - and _ insensitive search
    }
    return 0;
}

option_base* option_list::find_by_shortcut(char shortcut)
{
    for(option_list_t::const_iterator i = options.begin(); i != options.end(); ++i)
    {
        option_base* opt = *i;

        if( shortcut == opt->get_switch_letter() )
            return opt;
    }
    return 0;
}

option_list::option_list_t option_list::get_options()
{
    return options;
}

//
// option_registry
//
static option_list* default_option_list = 0;
static void delete_default_option_list()
{
    delete default_option_list;
}

option_list& option_registry::get()
{
    if( default_option_list == 0 ) {
        default_option_list = new option_list();
        std::atexit(delete_default_option_list);
    }
    return *default_option_list;
}

} // end namespace tinfra

// jedit: :tabSize=8:indentSize=4:noTabs=true:mode=c++:

<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkDecoratorTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <iostream>
#include "itkVector.h"
#include "itkAffineTransform.h"
#include "itkSimpleDataObjectDecorator.h"
#include "itkDataObjectDecorator.h"
#include "itkAutoPointerDataObjectDecorator.h"

// Problems with gcc 2.95. Temporary workaround
#if !(defined(__GNUC__) && __GNUC__ <= 2)
#define OK
#endif

#ifdef OK
namespace {
template <class charT, class traits, class T, class A>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>&os, const std::vector<T,A> &p)
{
  os << "vector<" << typeid(T).name() << "> with " << p.size() << " elements " << std::endl;
  return os;
}
}
#endif

int itkDecoratorTest(int, char* [] )
{
  int status = 0;

  std::cout << "----------------------------------------------------"
            << std::endl;

  typedef itk::SimpleDataObjectDecorator<float> FloatObjectType;

  FloatObjectType::Pointer f = FloatObjectType::New();
  f->Set(5.0);

  std::cout << "Value of f: " << f->Get() << std::endl;
  std::cout << "FloatDataObject: " << f << std::endl;

  std::cout << "----------------------------------------------------"
            << std::endl;

  typedef itk::AffineTransform<double, 3> TransformType;
  typedef itk::DataObjectDecorator<TransformType> TransformObjectType;

  TransformObjectType::Pointer decoratedTransform = TransformObjectType::New();
  TransformType * transformObject = TransformType::New();
  const TransformType * constTransformObject = transformObject;

  transformObject->Scale( 5.0 );

  decoratedTransform->Set( constTransformObject );

  std::cout << "Value of decoratedTransform: ";
  decoratedTransform->Get()->Print(std::cout);
  std::cout << "TransformDataObject: " << decoratedTransform;

  std::cout << "----------------------------------------------------"
            << std::endl;

  typedef std::vector<float> VectorType;
  typedef VectorType* VectorPointer;
  typedef itk::SimpleDataObjectDecorator<VectorType> VectorObjectType;
  typedef itk::AutoPointerDataObjectDecorator<VectorType> VectorPointerObjectType;

  VectorType v;
  v.resize(5);
#ifdef OK
  std::cout << v << std::endl;
#endif
  VectorObjectType::Pointer vo = VectorObjectType::New();
  vo->Set(v);
#ifdef OK
  std::cout << vo;
#endif
  std::cout << "----------------------------------------------------"
            << std::endl;

  // The following code block will NOT cause a memory leak because the
  // ownership of the dynamically allocated memory is passed to the
  // AutoPointerDataObjectDecorator
  {
  VectorPointer vp;
  vp = new VectorType;
  vp->resize(3);
#ifdef OK
  std::cout << *vp << std::endl;
#endif

  VectorPointerObjectType::Pointer vop = VectorPointerObjectType::New();
  vop->Set(vp);

#ifdef OK
  std::cout << vop;
#endif
  }

  std::cout << "----------------------------------------------------"
            << std::endl;

  // The following code block will cause a memory leak because the
  // decorator does not deallocate the memory that was passed in on a
  // pointer. The AutoPointerDataObjectDecorator does delete the memory.
  //typedef itk::SimpleDataObjectDecorator<VectorPointer> VectorPointerObjectType2;
  //{
  //VectorPointer vp2;
  //vp2 = new VectorType;
  //vp2->resize(4);
  //std::cout << *vp2 << std::endl;

  //VectorPointerObjectType2::Pointer vop2 = VectorPointerObjectType2::New();
  //vop2->Set(vp2);

  //std::cout << vop2;
  //}

  return status;
}
<commit_msg>BUG: Transform object was not being assigned to a SmartPointer after its      construction from a New() operator call.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkDecoratorTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#include <iostream>
#include "itkVector.h"
#include "itkAffineTransform.h"
#include "itkSimpleDataObjectDecorator.h"
#include "itkDataObjectDecorator.h"
#include "itkAutoPointerDataObjectDecorator.h"

// Problems with gcc 2.95. Temporary workaround
#if !(defined(__GNUC__) && __GNUC__ <= 2)
#define OK
#endif

#ifdef OK
namespace {
template <class charT, class traits, class T, class A>
std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>&os, const std::vector<T,A> &p)
{
  os << "vector<" << typeid(T).name() << "> with " << p.size() << " elements " << std::endl;
  return os;
}
}
#endif

int itkDecoratorTest(int, char* [] )
{
  int status = 0;

  std::cout << "----------------------------------------------------"
            << std::endl;

  typedef itk::SimpleDataObjectDecorator<float> FloatObjectType;

  FloatObjectType::Pointer f = FloatObjectType::New();
  f->Set(5.0);

  std::cout << "Value of f: " << f->Get() << std::endl;
  std::cout << "FloatDataObject: " << f << std::endl;

  std::cout << "----------------------------------------------------"
            << std::endl;

  typedef itk::AffineTransform<double, 3> TransformType;
  typedef itk::DataObjectDecorator<TransformType> TransformObjectType;

  TransformObjectType::Pointer decoratedTransform = TransformObjectType::New();
  TransformType::Pointer transformObject = TransformType::New();
  const TransformType * constTransformObject = transformObject;

  transformObject->Scale( 5.0 );

  decoratedTransform->Set( constTransformObject );

  std::cout << "Value of decoratedTransform: ";
  decoratedTransform->Get()->Print(std::cout);
  std::cout << "TransformDataObject: " << decoratedTransform;

  std::cout << "----------------------------------------------------"
            << std::endl;

  typedef std::vector<float> VectorType;
  typedef VectorType* VectorPointer;
  typedef itk::SimpleDataObjectDecorator<VectorType> VectorObjectType;
  typedef itk::AutoPointerDataObjectDecorator<VectorType> VectorPointerObjectType;

  VectorType v;
  v.resize(5);
#ifdef OK
  std::cout << v << std::endl;
#endif
  VectorObjectType::Pointer vo = VectorObjectType::New();
  vo->Set(v);
#ifdef OK
  std::cout << vo;
#endif
  std::cout << "----------------------------------------------------"
            << std::endl;

  // The following code block will NOT cause a memory leak because the
  // ownership of the dynamically allocated memory is passed to the
  // AutoPointerDataObjectDecorator
  {
  VectorPointer vp;
  vp = new VectorType;
  vp->resize(3);
#ifdef OK
  std::cout << *vp << std::endl;
#endif

  VectorPointerObjectType::Pointer vop = VectorPointerObjectType::New();
  vop->Set(vp);

#ifdef OK
  std::cout << vop;
#endif
  }

  std::cout << "----------------------------------------------------"
            << std::endl;

  // The following code block will cause a memory leak because the
  // decorator does not deallocate the memory that was passed in on a
  // pointer. The AutoPointerDataObjectDecorator does delete the memory.
  //typedef itk::SimpleDataObjectDecorator<VectorPointer> VectorPointerObjectType2;
  //{
  //VectorPointer vp2;
  //vp2 = new VectorType;
  //vp2->resize(4);
  //std::cout << *vp2 << std::endl;

  //VectorPointerObjectType2::Pointer vop2 = VectorPointerObjectType2::New();
  //vop2->Set(vp2);

  //std::cout << vop2;
  //}

  return status;
}
<|endoftext|>