<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) 2015 Cloudius Systems, Ltd.
 */

#include <seastar/testing/test_case.hh>
#include <seastar/testing/thread_test_case.hh>
#include <seastar/core/distributed.hh>
#include <seastar/core/loop.hh>
#include <seastar/core/semaphore.hh>
#include <seastar/core/sleep.hh>
#include <seastar/core/thread.hh>
#include <seastar/core/print.hh>
#include <seastar/util/defer.hh>
#include <seastar/util/closeable.hh>
#include <seastar/util/later.hh>
#include <mutex>

using namespace seastar;
using namespace std::chrono_literals;

struct async_service : public seastar::async_sharded_service<async_service> {
    thread_local static bool deleted;
    ~async_service() {
        deleted = true;
    }
    void run() {
        auto ref = shared_from_this();
        // Wait a while and check.
        (void)sleep(std::chrono::milliseconds(100 + 100 * this_shard_id())).then([this, ref] {
           check();
        });
    }
    virtual void check() {
        assert(!deleted);
    }
    future<> stop() { return make_ready_future<>(); }
};

thread_local bool async_service::deleted = false;

struct X {
    sstring echo(sstring arg) {
        return arg;
    }
    int cpu_id_squared() const {
        auto id = this_shard_id();
        return id * id;
    }
    future<> stop() { return make_ready_future<>(); }
};

template <typename T, typename Func>
future<> do_with_distributed(Func&& func) {
    auto x = make_shared<distributed<T>>();
    return func(*x).finally([x] {
        return x->stop();
    }).finally([x]{});
}

SEASTAR_TEST_CASE(test_that_each_core_gets_the_arguments) {
    return do_with_distributed<X>([] (auto& x) {
        return x.start().then([&x] {
            return x.map_reduce([] (sstring msg){
                if (msg != "hello") {
                    throw std::runtime_error("wrong message");
                }
            }, &X::echo, sstring("hello"));
        });
    });
}

SEASTAR_TEST_CASE(test_functor_version) {
    return do_with_distributed<X>([] (auto& x) {
        return x.start().then([&x] {
            return x.map_reduce([] (sstring msg){
                if (msg != "hello") {
                    throw std::runtime_error("wrong message");
                }
            }, [] (X& x) { return x.echo("hello"); });
        });
    });
}

struct Y {
    sstring s;
    Y(sstring s) : s(std::move(s)) {}
    future<> stop() { return make_ready_future<>(); }
};

SEASTAR_TEST_CASE(test_constructor_argument_is_passed_to_each_core) {
    return do_with_distributed<Y>([] (auto& y) {
        return y.start(sstring("hello")).then([&y] {
            return y.invoke_on_all([] (Y& y) {
                if (y.s != "hello") {
                    throw std::runtime_error(format("expected message mismatch, is \"%s\"", y.s));
                }
            });
        });
    });
}

SEASTAR_TEST_CASE(test_map_reduce) {
    return do_with_distributed<X>([] (distributed<X>& x) {
        return x.start().then([&x] {
            return x.map_reduce0(std::mem_fn(&X::cpu_id_squared),
                                 0,
                                 std::plus<int>()).then([] (int result) {
                int n = smp::count - 1;
                if (result != (n * (n + 1) * (2*n + 1)) / 6) {
                    throw std::runtime_error("map_reduce failed");
                }
            });
        });
    });
}

SEASTAR_TEST_CASE(test_map_reduce_lifetime) {
    struct map {
        bool destroyed = false;
        ~map() {
            destroyed = true;
        }
        auto operator()(const X& x) {
            return yield().then([this, &x] {
                BOOST_REQUIRE(!destroyed);
                return x.cpu_id_squared();
            });
        }
    };
    struct reduce {
        long& res;
        bool destroyed = false;
        ~reduce() {
            destroyed = true;
        }
        auto operator()(int x) {
            return yield().then([this, x] {
                BOOST_REQUIRE(!destroyed);
                res += x;
            });
        }
    };
    return do_with_distributed<X>([] (distributed<X>& x) {
        return x.start().then([&x] {
            return do_with(0L, [&x] (auto& result) {
                return x.map_reduce(reduce{result}, map{}).then([&result] {
                    long n = smp::count - 1;
                    long expected = (n * (n + 1) * (2*n + 1)) / 6;
                    BOOST_REQUIRE_EQUAL(result, expected);
                });
            });
        });
    });
}

SEASTAR_TEST_CASE(test_map_reduce0_lifetime) {
    struct map {
        bool destroyed = false;
        ~map() {
            destroyed = true;
        }
        auto operator()(const X& x) const {
            return yield().then([this, &x] {
                BOOST_REQUIRE(!destroyed);
                return x.cpu_id_squared();
            });
        }
    };
    struct reduce {
        bool destroyed = false;
        ~reduce() {
            destroyed = true;
        }
        auto operator()(long res, int x) {
            BOOST_REQUIRE(!destroyed);
            return res + x;
        }
    };
    return do_with_distributed<X>([] (distributed<X>& x) {
        return x.start().then([&x] {
            return x.map_reduce0(map{}, 0L, reduce{}).then([] (long result) {
                long n = smp::count - 1;
                long expected = (n * (n + 1) * (2*n + 1)) / 6;
                BOOST_REQUIRE_EQUAL(result, expected);
            });
        });
    });
}

SEASTAR_TEST_CASE(test_async) {
    return do_with_distributed<async_service>([] (distributed<async_service>& x) {
        return x.start().then([&x] {
            return x.invoke_on_all(&async_service::run);
        });
    }).then([] {
        return sleep(std::chrono::milliseconds(100 * (smp::count + 1)));
    });
}

SEASTAR_TEST_CASE(test_invoke_on_others) {
    return seastar::async([] {
        struct my_service {
            int counter = 0;
            void up() { ++counter; }
            future<> stop() { return make_ready_future<>(); }
        };
        for (unsigned c = 0; c < smp::count; ++c) {
            smp::submit_to(c, [c] {
                return seastar::async([c] {
                    sharded<my_service> s;
                    s.start().get();
                    s.invoke_on_others([](auto& s) { s.up(); }).get();
                    if (s.local().counter != 0) {
                        throw std::runtime_error("local modified");
                    }
                    s.invoke_on_all([c](auto& remote) {
                        if (this_shard_id() != c) {
                            if (remote.counter != 1) {
                                throw std::runtime_error("remote not modified");
                            }
                        }
                    }).get();
                    s.stop().get();
                });
            }).get();
        }
    });
}

SEASTAR_TEST_CASE(test_smp_invoke_on_others) {
    return seastar::async([] {
        std::vector<std::vector<int>> calls;
        calls.reserve(smp::count);
        for (unsigned i = 0; i < smp::count; i++) {
            auto& sv = calls.emplace_back();
            sv.reserve(smp::count);
        }

        smp::invoke_on_all([&calls] {
            return smp::invoke_on_others([&calls, from = this_shard_id()] {
                calls[this_shard_id()].emplace_back(from);
            });
        }).get();

        for (unsigned i = 0; i < smp::count; i++) {
            BOOST_REQUIRE_EQUAL(calls[i].size(), smp::count - 1);
            for (unsigned f = 0; f < smp::count; f++) {
                auto r = std::find(calls[i].begin(), calls[i].end(), f);
                BOOST_REQUIRE_EQUAL(r == calls[i].end(), i == f);
            }
        }
    });
}

struct remote_worker {
    unsigned current = 0;
    unsigned max_concurrent_observed = 0;
    unsigned expected_max;
    semaphore sem{0};
    remote_worker(unsigned expected_max) : expected_max(expected_max) {
    }
    future<> do_work() {
        ++current;
        max_concurrent_observed = std::max(current, max_concurrent_observed);
        if (max_concurrent_observed >= expected_max && sem.current() == 0) {
            sem.signal(semaphore::max_counter());
        }
        return sem.wait().then([this] {
            // Sleep a bit to check if the concurrency goes over the max
            return sleep(100ms).then([this] {
                max_concurrent_observed = std::max(current, max_concurrent_observed);
                --current;
            });
        });
    }
    future<> do_remote_work(shard_id t, smp_service_group ssg) {
        return smp::submit_to(t,  ssg, [this] {
            return do_work();
        });
    }
};

SEASTAR_TEST_CASE(test_smp_service_groups) {
    return async([] {
        smp_service_group_config ssgc1;
        ssgc1.max_nonlocal_requests = 1;
        auto ssg1 = create_smp_service_group(ssgc1).get0();
        smp_service_group_config ssgc2;
        ssgc2.max_nonlocal_requests = 1000;
        auto ssg2 = create_smp_service_group(ssgc2).get0();
        shard_id other_shard = smp::count - 1;
        remote_worker rm1(1);
        remote_worker rm2(1000);
        auto bunch1 = parallel_for_each(boost::irange(0, 20), [&] (int ignore) { return rm1.do_remote_work(other_shard, ssg1); });
        auto bunch2 = parallel_for_each(boost::irange(0, 2000), [&] (int ignore) { return rm2.do_remote_work(other_shard, ssg2); });
        bunch1.get();
        bunch2.get();
        if (smp::count > 1) {
            assert(rm1.max_concurrent_observed == 1);
            assert(rm2.max_concurrent_observed == 1000);
        }
        destroy_smp_service_group(ssg1).get();
        destroy_smp_service_group(ssg2).get();
    });
}

SEASTAR_TEST_CASE(test_smp_service_groups_re_construction) {
    // During development of the feature, we saw a bug where the vector
    // holding the groups did not expand correctly. This test triggers the
    // bug.
    return async([] {
        auto ssg1 = create_smp_service_group({}).get0();
        auto ssg2 = create_smp_service_group({}).get0();
        destroy_smp_service_group(ssg1).get();
        auto ssg3 = create_smp_service_group({}).get0();
        destroy_smp_service_group(ssg2).get();
        destroy_smp_service_group(ssg3).get();
    });
}

SEASTAR_TEST_CASE(test_smp_timeout) {
    return async([] {
        smp_service_group_config ssgc1;
        ssgc1.max_nonlocal_requests = 1;
        auto ssg1 = create_smp_service_group(ssgc1).get0();

        auto _ = defer([ssg1] () noexcept {
            destroy_smp_service_group(ssg1).get();
        });

        const shard_id other_shard = smp::count - 1;

        // Ugly but beats using sleeps.
        std::mutex mut;
        std::unique_lock<std::mutex> lk(mut);

        // Submitted to the remote shard.
        auto fut1 = smp::submit_to(other_shard, ssg1, [&mut] {
            std::cout << "Running request no. 1" << std::endl;
            std::unique_lock<std::mutex> lk(mut);
            std::cout << "Request no. 1 done" << std::endl;
        });
        // Consume the only unit from the semaphore.
        auto fut2 = smp::submit_to(other_shard, ssg1, [] {
            std::cout << "Running request no. 2 - done" << std::endl;
        });

        auto fut_timedout = smp::submit_to(other_shard, smp_submit_to_options(ssg1, smp_timeout_clock::now() + 10ms), [] {
            std::cout << "Running timed-out request - done" << std::endl;
        });

        {
            auto notify = defer([lk = std::move(lk)] () noexcept { });

            try {
                fut_timedout.get();
                throw std::runtime_error("smp::submit_to() didn't timeout as expected");
            } catch (semaphore_timed_out& e) {
                std::cout << "Expected timeout received: " << e.what() << std::endl;
            } catch (...) {
                std::throw_with_nested(std::runtime_error("smp::submit_to() failed with unexpected exception"));
            }
        }

        fut1.get();
        fut2.get();
    });
}

SEASTAR_THREAD_TEST_CASE(test_sharded_parameter) {
    struct dependency {
        unsigned val = this_shard_id() * 7;
    };
    struct some_service {
        bool ok = false;
        some_service(unsigned non_shard_dependent, unsigned shard_dependent, dependency& dep, unsigned shard_dependent_2) {
            ok =
                    non_shard_dependent == 43
                    && shard_dependent == this_shard_id() * 3
                    && dep.val == this_shard_id() * 7
                    && shard_dependent_2 == -dep.val;
        }
    };
    sharded<dependency> s_dep;
    s_dep.start().get();
    auto undo1 = deferred_stop(s_dep);

    sharded<some_service> s_service;
    s_service.start(
            43, // should be copied verbatim
            sharded_parameter([] { return this_shard_id() * 3; }),
            std::ref(s_dep),
            sharded_parameter([] (dependency& d) { return -d.val; }, std::ref(s_dep))
            ).get();
    auto undo2 = deferred_stop(s_service);

    auto all_ok = s_service.map_reduce0(std::mem_fn(&some_service::ok), true, std::multiplies<>()).get0();
    BOOST_REQUIRE(all_ok);
}
<commit_msg>tests: distributed_test: add test_map_lifetime<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) 2015 Cloudius Systems, Ltd.
 */

#include <seastar/testing/test_case.hh>
#include <seastar/testing/thread_test_case.hh>
#include <seastar/core/distributed.hh>
#include <seastar/core/loop.hh>
#include <seastar/core/semaphore.hh>
#include <seastar/core/sleep.hh>
#include <seastar/core/thread.hh>
#include <seastar/core/print.hh>
#include <seastar/util/defer.hh>
#include <seastar/util/closeable.hh>
#include <seastar/util/later.hh>
#include <mutex>

using namespace seastar;
using namespace std::chrono_literals;

struct async_service : public seastar::async_sharded_service<async_service> {
    thread_local static bool deleted;
    ~async_service() {
        deleted = true;
    }
    void run() {
        auto ref = shared_from_this();
        // Wait a while and check.
        (void)sleep(std::chrono::milliseconds(100 + 100 * this_shard_id())).then([this, ref] {
           check();
        });
    }
    virtual void check() {
        assert(!deleted);
    }
    future<> stop() { return make_ready_future<>(); }
};

thread_local bool async_service::deleted = false;

struct X {
    sstring echo(sstring arg) {
        return arg;
    }
    int cpu_id_squared() const {
        auto id = this_shard_id();
        return id * id;
    }
    future<> stop() { return make_ready_future<>(); }
};

template <typename T, typename Func>
future<> do_with_distributed(Func&& func) {
    auto x = make_shared<distributed<T>>();
    return func(*x).finally([x] {
        return x->stop();
    }).finally([x]{});
}

SEASTAR_TEST_CASE(test_that_each_core_gets_the_arguments) {
    return do_with_distributed<X>([] (auto& x) {
        return x.start().then([&x] {
            return x.map_reduce([] (sstring msg){
                if (msg != "hello") {
                    throw std::runtime_error("wrong message");
                }
            }, &X::echo, sstring("hello"));
        });
    });
}

SEASTAR_TEST_CASE(test_functor_version) {
    return do_with_distributed<X>([] (auto& x) {
        return x.start().then([&x] {
            return x.map_reduce([] (sstring msg){
                if (msg != "hello") {
                    throw std::runtime_error("wrong message");
                }
            }, [] (X& x) { return x.echo("hello"); });
        });
    });
}

struct Y {
    sstring s;
    Y(sstring s) : s(std::move(s)) {}
    future<> stop() { return make_ready_future<>(); }
};

SEASTAR_TEST_CASE(test_constructor_argument_is_passed_to_each_core) {
    return do_with_distributed<Y>([] (auto& y) {
        return y.start(sstring("hello")).then([&y] {
            return y.invoke_on_all([] (Y& y) {
                if (y.s != "hello") {
                    throw std::runtime_error(format("expected message mismatch, is \"%s\"", y.s));
                }
            });
        });
    });
}

SEASTAR_TEST_CASE(test_map_reduce) {
    return do_with_distributed<X>([] (distributed<X>& x) {
        return x.start().then([&x] {
            return x.map_reduce0(std::mem_fn(&X::cpu_id_squared),
                                 0,
                                 std::plus<int>()).then([] (int result) {
                int n = smp::count - 1;
                if (result != (n * (n + 1) * (2*n + 1)) / 6) {
                    throw std::runtime_error("map_reduce failed");
                }
            });
        });
    });
}

SEASTAR_TEST_CASE(test_map_reduce_lifetime) {
    struct map {
        bool destroyed = false;
        ~map() {
            destroyed = true;
        }
        auto operator()(const X& x) {
            return yield().then([this, &x] {
                BOOST_REQUIRE(!destroyed);
                return x.cpu_id_squared();
            });
        }
    };
    struct reduce {
        long& res;
        bool destroyed = false;
        ~reduce() {
            destroyed = true;
        }
        auto operator()(int x) {
            return yield().then([this, x] {
                BOOST_REQUIRE(!destroyed);
                res += x;
            });
        }
    };
    return do_with_distributed<X>([] (distributed<X>& x) {
        return x.start().then([&x] {
            return do_with(0L, [&x] (auto& result) {
                return x.map_reduce(reduce{result}, map{}).then([&result] {
                    long n = smp::count - 1;
                    long expected = (n * (n + 1) * (2*n + 1)) / 6;
                    BOOST_REQUIRE_EQUAL(result, expected);
                });
            });
        });
    });
}

SEASTAR_TEST_CASE(test_map_reduce0_lifetime) {
    struct map {
        bool destroyed = false;
        ~map() {
            destroyed = true;
        }
        auto operator()(const X& x) const {
            return yield().then([this, &x] {
                BOOST_REQUIRE(!destroyed);
                return x.cpu_id_squared();
            });
        }
    };
    struct reduce {
        bool destroyed = false;
        ~reduce() {
            destroyed = true;
        }
        auto operator()(long res, int x) {
            BOOST_REQUIRE(!destroyed);
            return res + x;
        }
    };
    return do_with_distributed<X>([] (distributed<X>& x) {
        return x.start().then([&x] {
            return x.map_reduce0(map{}, 0L, reduce{}).then([] (long result) {
                long n = smp::count - 1;
                long expected = (n * (n + 1) * (2*n + 1)) / 6;
                BOOST_REQUIRE_EQUAL(result, expected);
            });
        });
    });
}

SEASTAR_TEST_CASE(test_map_lifetime) {
    struct map {
        bool destroyed = false;
        ~map() {
            destroyed = true;
        }
        auto operator()(const X& x) const {
            return yield().then([this, &x] {
                BOOST_REQUIRE(!destroyed);
                return x.cpu_id_squared();
            });
        }
    };
    return do_with_distributed<X>([] (distributed<X>& x) {
        return x.start().then([&x] {
            return x.map(map{}).then([] (std::vector<int> result) {
                BOOST_REQUIRE_EQUAL(result.size(), smp::count);
                for (size_t i = 0; i < (size_t)smp::count; i++) {
                    BOOST_REQUIRE_EQUAL(result[i], i * i);
                }
            });
        });
    });
}

SEASTAR_TEST_CASE(test_async) {
    return do_with_distributed<async_service>([] (distributed<async_service>& x) {
        return x.start().then([&x] {
            return x.invoke_on_all(&async_service::run);
        });
    }).then([] {
        return sleep(std::chrono::milliseconds(100 * (smp::count + 1)));
    });
}

SEASTAR_TEST_CASE(test_invoke_on_others) {
    return seastar::async([] {
        struct my_service {
            int counter = 0;
            void up() { ++counter; }
            future<> stop() { return make_ready_future<>(); }
        };
        for (unsigned c = 0; c < smp::count; ++c) {
            smp::submit_to(c, [c] {
                return seastar::async([c] {
                    sharded<my_service> s;
                    s.start().get();
                    s.invoke_on_others([](auto& s) { s.up(); }).get();
                    if (s.local().counter != 0) {
                        throw std::runtime_error("local modified");
                    }
                    s.invoke_on_all([c](auto& remote) {
                        if (this_shard_id() != c) {
                            if (remote.counter != 1) {
                                throw std::runtime_error("remote not modified");
                            }
                        }
                    }).get();
                    s.stop().get();
                });
            }).get();
        }
    });
}

SEASTAR_TEST_CASE(test_smp_invoke_on_others) {
    return seastar::async([] {
        std::vector<std::vector<int>> calls;
        calls.reserve(smp::count);
        for (unsigned i = 0; i < smp::count; i++) {
            auto& sv = calls.emplace_back();
            sv.reserve(smp::count);
        }

        smp::invoke_on_all([&calls] {
            return smp::invoke_on_others([&calls, from = this_shard_id()] {
                calls[this_shard_id()].emplace_back(from);
            });
        }).get();

        for (unsigned i = 0; i < smp::count; i++) {
            BOOST_REQUIRE_EQUAL(calls[i].size(), smp::count - 1);
            for (unsigned f = 0; f < smp::count; f++) {
                auto r = std::find(calls[i].begin(), calls[i].end(), f);
                BOOST_REQUIRE_EQUAL(r == calls[i].end(), i == f);
            }
        }
    });
}

struct remote_worker {
    unsigned current = 0;
    unsigned max_concurrent_observed = 0;
    unsigned expected_max;
    semaphore sem{0};
    remote_worker(unsigned expected_max) : expected_max(expected_max) {
    }
    future<> do_work() {
        ++current;
        max_concurrent_observed = std::max(current, max_concurrent_observed);
        if (max_concurrent_observed >= expected_max && sem.current() == 0) {
            sem.signal(semaphore::max_counter());
        }
        return sem.wait().then([this] {
            // Sleep a bit to check if the concurrency goes over the max
            return sleep(100ms).then([this] {
                max_concurrent_observed = std::max(current, max_concurrent_observed);
                --current;
            });
        });
    }
    future<> do_remote_work(shard_id t, smp_service_group ssg) {
        return smp::submit_to(t,  ssg, [this] {
            return do_work();
        });
    }
};

SEASTAR_TEST_CASE(test_smp_service_groups) {
    return async([] {
        smp_service_group_config ssgc1;
        ssgc1.max_nonlocal_requests = 1;
        auto ssg1 = create_smp_service_group(ssgc1).get0();
        smp_service_group_config ssgc2;
        ssgc2.max_nonlocal_requests = 1000;
        auto ssg2 = create_smp_service_group(ssgc2).get0();
        shard_id other_shard = smp::count - 1;
        remote_worker rm1(1);
        remote_worker rm2(1000);
        auto bunch1 = parallel_for_each(boost::irange(0, 20), [&] (int ignore) { return rm1.do_remote_work(other_shard, ssg1); });
        auto bunch2 = parallel_for_each(boost::irange(0, 2000), [&] (int ignore) { return rm2.do_remote_work(other_shard, ssg2); });
        bunch1.get();
        bunch2.get();
        if (smp::count > 1) {
            assert(rm1.max_concurrent_observed == 1);
            assert(rm2.max_concurrent_observed == 1000);
        }
        destroy_smp_service_group(ssg1).get();
        destroy_smp_service_group(ssg2).get();
    });
}

SEASTAR_TEST_CASE(test_smp_service_groups_re_construction) {
    // During development of the feature, we saw a bug where the vector
    // holding the groups did not expand correctly. This test triggers the
    // bug.
    return async([] {
        auto ssg1 = create_smp_service_group({}).get0();
        auto ssg2 = create_smp_service_group({}).get0();
        destroy_smp_service_group(ssg1).get();
        auto ssg3 = create_smp_service_group({}).get0();
        destroy_smp_service_group(ssg2).get();
        destroy_smp_service_group(ssg3).get();
    });
}

SEASTAR_TEST_CASE(test_smp_timeout) {
    return async([] {
        smp_service_group_config ssgc1;
        ssgc1.max_nonlocal_requests = 1;
        auto ssg1 = create_smp_service_group(ssgc1).get0();

        auto _ = defer([ssg1] () noexcept {
            destroy_smp_service_group(ssg1).get();
        });

        const shard_id other_shard = smp::count - 1;

        // Ugly but beats using sleeps.
        std::mutex mut;
        std::unique_lock<std::mutex> lk(mut);

        // Submitted to the remote shard.
        auto fut1 = smp::submit_to(other_shard, ssg1, [&mut] {
            std::cout << "Running request no. 1" << std::endl;
            std::unique_lock<std::mutex> lk(mut);
            std::cout << "Request no. 1 done" << std::endl;
        });
        // Consume the only unit from the semaphore.
        auto fut2 = smp::submit_to(other_shard, ssg1, [] {
            std::cout << "Running request no. 2 - done" << std::endl;
        });

        auto fut_timedout = smp::submit_to(other_shard, smp_submit_to_options(ssg1, smp_timeout_clock::now() + 10ms), [] {
            std::cout << "Running timed-out request - done" << std::endl;
        });

        {
            auto notify = defer([lk = std::move(lk)] () noexcept { });

            try {
                fut_timedout.get();
                throw std::runtime_error("smp::submit_to() didn't timeout as expected");
            } catch (semaphore_timed_out& e) {
                std::cout << "Expected timeout received: " << e.what() << std::endl;
            } catch (...) {
                std::throw_with_nested(std::runtime_error("smp::submit_to() failed with unexpected exception"));
            }
        }

        fut1.get();
        fut2.get();
    });
}

SEASTAR_THREAD_TEST_CASE(test_sharded_parameter) {
    struct dependency {
        unsigned val = this_shard_id() * 7;
    };
    struct some_service {
        bool ok = false;
        some_service(unsigned non_shard_dependent, unsigned shard_dependent, dependency& dep, unsigned shard_dependent_2) {
            ok =
                    non_shard_dependent == 43
                    && shard_dependent == this_shard_id() * 3
                    && dep.val == this_shard_id() * 7
                    && shard_dependent_2 == -dep.val;
        }
    };
    sharded<dependency> s_dep;
    s_dep.start().get();
    auto undo1 = deferred_stop(s_dep);

    sharded<some_service> s_service;
    s_service.start(
            43, // should be copied verbatim
            sharded_parameter([] { return this_shard_id() * 3; }),
            std::ref(s_dep),
            sharded_parameter([] (dependency& d) { return -d.val; }, std::ref(s_dep))
            ).get();
    auto undo2 = deferred_stop(s_service);

    auto all_ok = s_service.map_reduce0(std::mem_fn(&some_service::ok), true, std::multiplies<>()).get0();
    BOOST_REQUIRE(all_ok);
}
<|endoftext|>


<commit_before>/**
 * Self-Organizing Maps on a cluster
 *  Copyright (C) 2013 Peter Wittek
 *
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <cmath>
#include <sstream>
#include <iostream>
#include <fstream>

#include "somoclu.h"

using namespace std;

/** Save a SOM codebook
 * @param cbFileName - name of the file to save
 * @param codebook - the codebook to save
 * @param nSomX - dimensions of SOM map in the x direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 */
int saveCodebook(char* cbFileName, float *codebook, unsigned int nSomX, unsigned int nSomY, unsigned int nDimensions)
{
	char temp[80];
	cout << "    Codebook file = " << cbFileName << endl;
	ofstream mapFile2(cbFileName);
	cout << "    Saving Codebook..." << endl;
	if (mapFile2.is_open()) {
		for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
			for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
				for (unsigned int d = 0; d < nDimensions; d++) {
					sprintf(temp, "%0.10f", codebook[som_y*nSomX*nDimensions+som_x*nDimensions+d]);
					mapFile2 << temp << "\t";
				}
			}
			mapFile2 << endl;
		}
		mapFile2.close();
		return 0;
	}
	else
	{
		return 1;
	}
}

/** Euclidean distance between vec1 and vec2
 * @param vec1
 * @param vec2
 * @param nDimensions
 * @return distance
 */

float get_distance(const float* vec1, const float* vec2,
                   unsigned int nDimensions)
{
  float distance = 0.0f;
  for (unsigned int d = 0; d < nDimensions; d++)
    distance += (vec1[d] - vec2[d]) * (vec1[d] - vec2[d]);
  return sqrt(distance);
}

/** Get weight vector from a codebook using x, y index
 * @param codebook - the codebook to save
 * @param som_y - y coordinate of a node in the map
 * @param som_x - x coordinate of a node in the map
 * @param nSomX - dimensions of SOM map in the x direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 * @return the weight vector
 */

float* get_wvec(float *codebook, unsigned int som_y, unsigned int som_x,
                unsigned int nSomX, unsigned int nSomY, unsigned int nDimensions)
{
  float* wvec = new float[nDimensions];
  for (unsigned int d = 0; d < nDimensions; d++)
      wvec[d] = codebook[som_y*nSomX*nDimensions+som_x*nDimensions+d]; /// CAUTION: (y,x) order
  return wvec;
}

/** Save u-matrix
 * @param fname
 * @param codebook - the codebook to save
 * @param nSomX - dimensions of SOM map in the x direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 */

int saveUMat(char* fname, float *codebook, unsigned int nSomX,
              unsigned int nSomY, unsigned int nDimensions)
{
  unsigned int D = 2;
  float min_dist = 1.5f;
  FILE* fp = fopen(fname, "wt");
  if (fp != 0) {
    for (unsigned int som_y1 = 0; som_y1 < nSomY; som_y1++) {
      for (unsigned int som_x1 = 0; som_x1 < nSomX; som_x1++) {
        float dist = 0.0f;
        unsigned int nodes_number = 0;
        int coords1[2];
        coords1[0] = som_x1;
        coords1[1] = som_y1;

        for (unsigned int som_y2 = 0; som_y2 < nSomY; som_y2++) {
            for (unsigned int som_x2 = 0; som_x2 < nSomX; som_x2++) {
              unsigned int coords2[2];
              coords2[0] = som_x2;
              coords2[1] = som_y2;

              if (som_x1 == som_x2 && som_y1 == som_y2) continue;

              float tmp = 0.0;
              for (unsigned int d = 0; d < D; d++) {
                  tmp += pow(coords1[d] - coords2[d], 2.0f);
              }
              tmp = sqrt(tmp);
              if (tmp <= min_dist) {
                  nodes_number++;
                  float* vec1 = get_wvec(codebook, som_y1, som_x1, nSomX, nSomY, nDimensions);
                  float* vec2 = get_wvec(codebook, som_y2, som_x2, nSomX, nSomY, nDimensions);
                  dist += get_distance(vec1, vec2, nDimensions);
                  delete [] vec1;
                  delete [] vec2;
              }
            }
        }
        dist /= (float)nodes_number;
        fprintf(fp, " %f", dist);
      }
      fprintf(fp, "\n");
    }
    fclose(fp);
    return 0;
  }
  else
    return -2;
}

/** Reads a matrix
 * @param inFileNae
 * @param nRows - returns the number of rows
 * @param nColumns - returns the number of columns
 * @return the matrix
 */

float *readMatrix(const char *inFileName, unsigned int &nRows, unsigned int &nColumns)
{
  ifstream file;
  file.open(inFileName);
  string line;
  int elements = 0;
  float tmp;
  while(getline(file,line)){
    stringstream linestream(line);
    string value;
    while(getline(linestream,value,' ')){
      //&& EOF != sscanf(str_float, "%f", &tmp)
      if(value.length()>0){
        istringstream myStream(value);
        myStream >> tmp;
        if (!myStream.fail()){
          elements++;
        }
      }
    }
    if (nRows==0){
      nColumns=elements;
    }
    nRows++;
  }
  float *data=new float[elements];
  file.close();file.open(inFileName);
  int j=0;
  while(getline(file,line)){
    stringstream linestream(line);
    string value;
    while(getline(linestream,value,' ')){
      if (value.length()>0){
        istringstream myStream(value);
        myStream >> tmp;
        if (!myStream.fail()){
          data[j++]=tmp;
        }
      }
    }
  }
  file.close();
  return data;
}

void readSparseMatrixDimensions(const char *filename, unsigned int &nRows,
                            unsigned int &nColumns) {
  ifstream file;
  file.open(filename);
  string line;
  int max_index=-1;
  while(getline(file,line)) {
    stringstream linestream(line);
    string value;
    int dummy_index;
    while(getline(linestream,value,' ')) {
      int separator=value.find(":");
      istringstream myStream(value.substr(0,separator));
      myStream >> dummy_index;
      if(dummy_index > max_index){
        max_index = dummy_index;
      }
    }
    ++nRows;
  }
  nColumns=max_index+1;
  file.close();
}

svm_node** readSparseMatrixChunk(const char *filename, unsigned int nRows,
                                 unsigned int nRowsToRead,
                                 unsigned int rowOffset) {
  ifstream file;
  file.open(filename);
  string line;
  for (unsigned int i=0; i<rowOffset; i++) {
    getline(file, line);
  }
/*  while(getline(file,line)) {
    stringstream linestream(line);
    string value;
    while(getline(linestream,value,' ')) {
      elements++;
    }
    elements++; // To account for the dummy row-closing element
    ++nRows;
  }
  file.close();file.open(filename);*/
  if (rowOffset+nRowsToRead >= nRows) {
    nRowsToRead = nRows-rowOffset;
  }
  svm_node **x_matrix = new svm_node *[nRowsToRead];
  for(unsigned int i=0;i<nRowsToRead;i++) {
    getline(file, line);
    stringstream tmplinestream(line);
    string value;
    int elements = 0;
    while(getline(tmplinestream,value,' ')) {
      elements++;
    }
    elements++; // To account for the closing dummy node in the row
    x_matrix[i] = new svm_node[elements];
    stringstream linestream(line);
    int j=0;
    while(getline(linestream,value,' ')) {
      int separator=value.find(":");
      istringstream myStream(value.substr(0,separator));
      myStream >> x_matrix[i][j].index;
      istringstream myStream2(value.substr(separator+1));
      myStream2 >> x_matrix[i][j].value;
      j++;
    }
    x_matrix[i][j].index = -1;
  }
  file.close();
  return x_matrix;
}
<commit_msg>Codebook saving function fixed<commit_after>/**
 * Self-Organizing Maps on a cluster
 *  Copyright (C) 2013 Peter Wittek
 *
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <cmath>
#include <sstream>
#include <iostream>
#include <fstream>

#include "somoclu.h"

using namespace std;

/** Save a SOM codebook
 * @param cbFileName - name of the file to save
 * @param codebook - the codebook to save
 * @param nSomX - dimensions of SOM map in the x direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 */
int saveCodebook(char* cbFileName, float *codebook, unsigned int nSomX, unsigned int nSomY, unsigned int nDimensions)
{
	char temp[80];
	cout << "    Codebook file = " << cbFileName << endl;
	ofstream mapFile(cbFileName);
	cout << "    Saving Codebook..." << endl;
	if (mapFile.is_open()) {
		for (unsigned int som_y = 0; som_y < nSomY; som_y++) {
			for (unsigned int som_x = 0; som_x < nSomX; som_x++) {
				for (unsigned int d = 0; d < nDimensions; d++) {
					sprintf(temp, "%0.10f", codebook[som_y*nSomX*nDimensions+som_x*nDimensions+d]);
					mapFile << temp << " ";
				}
			}
			mapFile << endl;
		}
		mapFile.close();
		return 0;
	}
	else
	{
		return 1;
	}
}

/** Euclidean distance between vec1 and vec2
 * @param vec1
 * @param vec2
 * @param nDimensions
 * @return distance
 */

float get_distance(const float* vec1, const float* vec2,
                   unsigned int nDimensions)
{
  float distance = 0.0f;
  for (unsigned int d = 0; d < nDimensions; d++)
    distance += (vec1[d] - vec2[d]) * (vec1[d] - vec2[d]);
  return sqrt(distance);
}

/** Get weight vector from a codebook using x, y index
 * @param codebook - the codebook to save
 * @param som_y - y coordinate of a node in the map
 * @param som_x - x coordinate of a node in the map
 * @param nSomX - dimensions of SOM map in the x direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 * @return the weight vector
 */

float* get_wvec(float *codebook, unsigned int som_y, unsigned int som_x,
                unsigned int nSomX, unsigned int nSomY, unsigned int nDimensions)
{
  float* wvec = new float[nDimensions];
  for (unsigned int d = 0; d < nDimensions; d++)
      wvec[d] = codebook[som_y*nSomX*nDimensions+som_x*nDimensions+d]; /// CAUTION: (y,x) order
  return wvec;
}

/** Save u-matrix
 * @param fname
 * @param codebook - the codebook to save
 * @param nSomX - dimensions of SOM map in the x direction
 * @param nSomY - dimensions of SOM map in the y direction
 * @param nDimensions - dimensions of a data instance
 */

int saveUMat(char* fname, float *codebook, unsigned int nSomX,
              unsigned int nSomY, unsigned int nDimensions)
{
  unsigned int D = 2;
  float min_dist = 1.5f;
  FILE* fp = fopen(fname, "wt");
  if (fp != 0) {
    for (unsigned int som_y1 = 0; som_y1 < nSomY; som_y1++) {
      for (unsigned int som_x1 = 0; som_x1 < nSomX; som_x1++) {
        float dist = 0.0f;
        unsigned int nodes_number = 0;
        int coords1[2];
        coords1[0] = som_x1;
        coords1[1] = som_y1;

        for (unsigned int som_y2 = 0; som_y2 < nSomY; som_y2++) {
            for (unsigned int som_x2 = 0; som_x2 < nSomX; som_x2++) {
              unsigned int coords2[2];
              coords2[0] = som_x2;
              coords2[1] = som_y2;

              if (som_x1 == som_x2 && som_y1 == som_y2) continue;

              float tmp = 0.0;
              for (unsigned int d = 0; d < D; d++) {
                  tmp += pow(coords1[d] - coords2[d], 2.0f);
              }
              tmp = sqrt(tmp);
              if (tmp <= min_dist) {
                  nodes_number++;
                  float* vec1 = get_wvec(codebook, som_y1, som_x1, nSomX, nSomY, nDimensions);
                  float* vec2 = get_wvec(codebook, som_y2, som_x2, nSomX, nSomY, nDimensions);
                  dist += get_distance(vec1, vec2, nDimensions);
                  delete [] vec1;
                  delete [] vec2;
              }
            }
        }
        dist /= (float)nodes_number;
        fprintf(fp, " %f", dist);
      }
      fprintf(fp, "\n");
    }
    fclose(fp);
    return 0;
  }
  else
    return -2;
}

/** Reads a matrix
 * @param inFileNae
 * @param nRows - returns the number of rows
 * @param nColumns - returns the number of columns
 * @return the matrix
 */

float *readMatrix(const char *inFileName, unsigned int &nRows, unsigned int &nColumns)
{
  ifstream file;
  file.open(inFileName);
  string line;
  int elements = 0;
  float tmp;
  while(getline(file,line)){
    stringstream linestream(line);
    string value;
    while(getline(linestream,value,' ')){
      //&& EOF != sscanf(str_float, "%f", &tmp)
      if(value.length()>0){
        istringstream myStream(value);
        myStream >> tmp;
        if (!myStream.fail()){
          elements++;
        }
      }
    }
    if (nRows==0){
      nColumns=elements;
    }
    nRows++;
  }
  float *data=new float[elements];
  file.close();file.open(inFileName);
  int j=0;
  while(getline(file,line)){
    stringstream linestream(line);
    string value;
    while(getline(linestream,value,' ')){
      if (value.length()>0){
        istringstream myStream(value);
        myStream >> tmp;
        if (!myStream.fail()){
          data[j++]=tmp;
        }
      }
    }
  }
  file.close();
  return data;
}

void readSparseMatrixDimensions(const char *filename, unsigned int &nRows,
                            unsigned int &nColumns) {
  ifstream file;
  file.open(filename);
  string line;
  int max_index=-1;
  while(getline(file,line)) {
    stringstream linestream(line);
    string value;
    int dummy_index;
    while(getline(linestream,value,' ')) {
      int separator=value.find(":");
      istringstream myStream(value.substr(0,separator));
      myStream >> dummy_index;
      if(dummy_index > max_index){
        max_index = dummy_index;
      }
    }
    ++nRows;
  }
  nColumns=max_index+1;
  file.close();
}

svm_node** readSparseMatrixChunk(const char *filename, unsigned int nRows,
                                 unsigned int nRowsToRead,
                                 unsigned int rowOffset) {
  ifstream file;
  file.open(filename);
  string line;
  for (unsigned int i=0; i<rowOffset; i++) {
    getline(file, line);
  }
/*  while(getline(file,line)) {
    stringstream linestream(line);
    string value;
    while(getline(linestream,value,' ')) {
      elements++;
    }
    elements++; // To account for the dummy row-closing element
    ++nRows;
  }
  file.close();file.open(filename);*/
  if (rowOffset+nRowsToRead >= nRows) {
    nRowsToRead = nRows-rowOffset;
  }
  svm_node **x_matrix = new svm_node *[nRowsToRead];
  for(unsigned int i=0;i<nRowsToRead;i++) {
    getline(file, line);
    stringstream tmplinestream(line);
    string value;
    int elements = 0;
    while(getline(tmplinestream,value,' ')) {
      elements++;
    }
    elements++; // To account for the closing dummy node in the row
    x_matrix[i] = new svm_node[elements];
    stringstream linestream(line);
    int j=0;
    while(getline(linestream,value,' ')) {
      int separator=value.find(":");
      istringstream myStream(value.substr(0,separator));
      myStream >> x_matrix[i][j].index;
      istringstream myStream2(value.substr(separator+1));
      myStream2 >> x_matrix[i][j].value;
      j++;
    }
    x_matrix[i][j].index = -1;
  }
  file.close();
  return x_matrix;
}
<|endoftext|>


<commit_before>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        exception_assertion_tests.cpp
 * @brief       iutest test 例外アサーションテスト
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2014-2016, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================

//======================================================================
// include
#include "../include/gtest/iutest_spi_switch.hpp"

#if IUTEST_HAS_EXCEPTIONS

static void ExceptionFunction(int i)
{
    switch( i )
    {
    case 0:
        return;
    case 1:
        throw 2;
        break;
    case 2:
        throw ::std::bad_exception();
        break;
    case 3:
        throw "error";
    case 4:
        throw ::std::string("error");
    case 5:
        throw 0.1f;
    default:
        break;
    }
}

IUTEST(Exception, Throw)
{
    //IUTEST_ASSERT_THROW(throw ::std::bad_exception(), ::std::bad_exception);
    IUTEST_ASSERT_THROW(ExceptionFunction(2), ::std::bad_exception);
    IUTEST_EXPECT_THROW(ExceptionFunction(2), ::std::bad_exception);
    IUTEST_INFORM_THROW(ExceptionFunction(2), ::std::bad_exception);
    IUTEST_ASSUME_THROW(ExceptionFunction(2), ::std::bad_exception);
}

IUTEST(Exception, AnyThrow)
{
    IUTEST_ASSERT_ANY_THROW(throw ::std::bad_exception());
    IUTEST_ASSERT_ANY_THROW(throw 1);
    IUTEST_ASSERT_ANY_THROW(ExceptionFunction(1));
    IUTEST_EXPECT_ANY_THROW(ExceptionFunction(1));
    IUTEST_INFORM_ANY_THROW(ExceptionFunction(1));
    IUTEST_ASSUME_ANY_THROW(ExceptionFunction(1));
}

IUTEST(Exception, NoThrow)
{
    IUTEST_ASSERT_NO_THROW((void)0);
    IUTEST_ASSERT_NO_THROW(ExceptionFunction(0));
    IUTEST_EXPECT_NO_THROW(ExceptionFunction(0));
    IUTEST_INFORM_NO_THROW(ExceptionFunction(0));
    IUTEST_ASSUME_NO_THROW(ExceptionFunction(0));
}

IUTEST(Exception, ValueEQ)
{
    IUTEST_ASSERT_THROW_VALUE_EQ(throw 2, int, 2);
    IUTEST_ASSERT_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
    IUTEST_EXPECT_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
    IUTEST_INFORM_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
    IUTEST_ASSUME_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
}

IUTEST(Exception, ValueNE)
{
    IUTEST_ASSERT_THROW_VALUE_NE(throw 2, int, 0);
    IUTEST_ASSERT_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
    IUTEST_EXPECT_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
    IUTEST_INFORM_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
    IUTEST_ASSUME_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
}

IUTEST(Exception, ValueSTREQ)
{
    IUTEST_ASSERT_THROW_VALUE_STREQ(throw "error", const char *, "error");
    IUTEST_ASSERT_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_EXPECT_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_INFORM_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_ASSUME_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_ASSERT_THROW_VALUE_STREQ(throw ::std::string("error"), ::std::string, "error");
    IUTEST_ASSERT_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
    IUTEST_EXPECT_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
    IUTEST_INFORM_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
    IUTEST_ASSUME_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
}

IUTEST(Exception, ValueSTRCASEEQ)
{
    IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(throw "error", const char *, "Error");
    IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
    IUTEST_EXPECT_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
    IUTEST_INFORM_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
    IUTEST_ASSUME_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
}

IUTEST(Exception, ValueFormat)
{
    IUTEST_ASSERT_THROW_PRED_FORMAT2(::iutest::internal::CmpHelperFloatingPointEQ<float>, ExceptionFunction(5), float, 0.1f);
}

IUTEST(ExceptionFailure, Throw)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW(throw "test", int), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW(throw "test", int), "" );
}

IUTEST(ExceptionFailure, AnyThrow)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_ANY_THROW((void)0), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_ANY_THROW((void)0), "" );
}

IUTEST(ExceptionFailure, NoThrow)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_NO_THROW(throw 1), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_NO_THROW(throw "error"), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_NO_THROW(throw ::std::bad_exception()), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_NO_THROW(throw 1), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_NO_THROW(throw "error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_NO_THROW(throw ::std::bad_exception()), "" );
}

IUTEST(ExceptionFailure, ValueEQ)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_EQ(throw 2, char, 2), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_EQ(throw 2,  int, 0), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_EQ(throw 2, char, 2), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_EQ(throw 2,  int, 0), "" );
}

IUTEST(ExceptionFailure, ValueSTREQ)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STREQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STREQ(throw "error", const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STREQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STREQ(throw "error", const char*, "Error"), "" );
}

IUTEST(ExceptionFailure, ValueSTRCASEEQ)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(throw "test", const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STRCASEEQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STRCASEEQ(throw "test", const char*, "Error"), "" );
}

#if IUTEST_HAS_NOEXCEPT && 0

void Noexcept() IUTEST_CXX_NOEXCEPT_SPEC
{
    throw 1;
}

IUTEST(NoThrowFailure, Noexcept)
{
    IUTEST_ASSERT_FATAL_FAILURE( IUTEST_ASSERT_NO_THROW(Noexcept()), "" );
}

#endif

#endif

#ifdef UNICODE
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    IUTEST_INIT(&argc, argv);
    return IUTEST_RUN_ALL_TESTS();
}

<commit_msg>update tes<commit_after>//======================================================================
//-----------------------------------------------------------------------
/**
 * @file        exception_assertion_tests.cpp
 * @brief       iutest test 例外アサーションテスト
 *
 * @author      t.shirayanagi
 * @par         copyright
 * Copyright (C) 2014-2016, Takazumi Shirayanagi\n
 * This software is released under the new BSD License,
 * see LICENSE
*/
//-----------------------------------------------------------------------
//======================================================================

//======================================================================
// include
#include "../include/gtest/iutest_spi_switch.hpp"

#if IUTEST_HAS_EXCEPTIONS

static void ExceptionFunction(int i)
{
    switch( i )
    {
    case 0:
        return;
    case 1:
        throw 2;
        break;
    case 2:
        throw ::std::bad_exception();
        break;
    case 3:
        throw "error";
    case 4:
        throw ::std::string("error");
    case 5:
        throw 0.1f;
    case -1:
        {
            int* p = reinterpret_cast<int*>(0x1234);
            *p = 1;
        }
        break;
    default:
        break;
    }
}

IUTEST(Exception, Throw)
{
    //IUTEST_ASSERT_THROW(throw ::std::bad_exception(), ::std::bad_exception);
    IUTEST_ASSERT_THROW(ExceptionFunction(2), ::std::bad_exception);
    IUTEST_EXPECT_THROW(ExceptionFunction(2), ::std::bad_exception);
    IUTEST_INFORM_THROW(ExceptionFunction(2), ::std::bad_exception);
    IUTEST_ASSUME_THROW(ExceptionFunction(2), ::std::bad_exception);
}

IUTEST(Exception, AnyThrow)
{
    IUTEST_ASSERT_ANY_THROW(throw ::std::bad_exception());
    IUTEST_ASSERT_ANY_THROW(throw 1);
    IUTEST_ASSERT_ANY_THROW(ExceptionFunction(1));
    IUTEST_EXPECT_ANY_THROW(ExceptionFunction(1));
    IUTEST_INFORM_ANY_THROW(ExceptionFunction(1));
    IUTEST_ASSUME_ANY_THROW(ExceptionFunction(1));
}

IUTEST(Exception, NoThrow)
{
    IUTEST_ASSERT_NO_THROW((void)0);
    IUTEST_ASSERT_NO_THROW(ExceptionFunction(0));
    IUTEST_EXPECT_NO_THROW(ExceptionFunction(0));
    IUTEST_INFORM_NO_THROW(ExceptionFunction(0));
    IUTEST_ASSUME_NO_THROW(ExceptionFunction(0));
}

IUTEST(Exception, ValueEQ)
{
    IUTEST_ASSERT_THROW_VALUE_EQ(throw 2, int, 2);
    IUTEST_ASSERT_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
    IUTEST_EXPECT_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
    IUTEST_INFORM_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
    IUTEST_ASSUME_THROW_VALUE_EQ(ExceptionFunction(1), int, 2);
}

IUTEST(Exception, ValueNE)
{
    IUTEST_ASSERT_THROW_VALUE_NE(throw 2, int, 0);
    IUTEST_ASSERT_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
    IUTEST_EXPECT_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
    IUTEST_INFORM_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
    IUTEST_ASSUME_THROW_VALUE_NE(ExceptionFunction(1), int, 0);
}

IUTEST(Exception, ValueSTREQ)
{
    IUTEST_ASSERT_THROW_VALUE_STREQ(throw "error", const char *, "error");
    IUTEST_ASSERT_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_EXPECT_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_INFORM_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_ASSUME_THROW_VALUE_STREQ(ExceptionFunction(3), const char *, "error");
    IUTEST_ASSERT_THROW_VALUE_STREQ(throw ::std::string("error"), ::std::string, "error");
    IUTEST_ASSERT_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
    IUTEST_EXPECT_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
    IUTEST_INFORM_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
    IUTEST_ASSUME_THROW_VALUE_STREQ(ExceptionFunction(4), ::std::string, "error");
}

IUTEST(Exception, ValueSTRCASEEQ)
{
    IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(throw "error", const char *, "Error");
    IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
    IUTEST_EXPECT_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
    IUTEST_INFORM_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
    IUTEST_ASSUME_THROW_VALUE_STRCASEEQ(ExceptionFunction(3), const char *, "Error");
}

IUTEST(Exception, ValueFormat)
{
    IUTEST_ASSERT_THROW_PRED_FORMAT2(::iutest::internal::CmpHelperFloatingPointEQ<float>, ExceptionFunction(5), float, 0.1f);
}

#if IUTEST_HAS_CATCH_SEH_EXCEPTION_ASERRTION
IUTEST(Exception, SEH)
{
    IUTEST_ASSERT_ANY_THROW(ExceptionFunction(-1));
    IUTEST_EXPECT_ANY_THROW(ExceptionFunction(-1));
    IUTEST_INFORM_ANY_THROW(ExceptionFunction(-1));
    IUTEST_ASSUME_ANY_THROW(ExceptionFunction(-1));
}
#endif

IUTEST(ExceptionFailure, Throw)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW(throw "test", int), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW(throw "test", int), "" );
}

IUTEST(ExceptionFailure, AnyThrow)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_ANY_THROW((void)0), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_ANY_THROW((void)0), "" );
}

IUTEST(ExceptionFailure, NoThrow)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_NO_THROW(throw 1), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_NO_THROW(throw "error"), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_NO_THROW(throw ::std::bad_exception()), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_NO_THROW(throw 1), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_NO_THROW(throw "error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_NO_THROW(throw ::std::bad_exception()), "" );
}

IUTEST(ExceptionFailure, ValueEQ)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_EQ(throw 2, char, 2), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_EQ(throw 2,  int, 0), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_EQ(throw 2, char, 2), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_EQ(throw 2,  int, 0), "" );
}

IUTEST(ExceptionFailure, ValueSTREQ)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STREQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STREQ(throw "error", const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STREQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STREQ(throw "error", const char*, "Error"), "" );
}

IUTEST(ExceptionFailure, ValueSTRCASEEQ)
{
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_FATAL_FAILURE   ( IUTEST_ASSERT_THROW_VALUE_STRCASEEQ(throw "test", const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STRCASEEQ(throw 1, const char*, "Error"), "" );
    IUTEST_ASSERT_NONFATAL_FAILURE( IUTEST_EXPECT_THROW_VALUE_STRCASEEQ(throw "test", const char*, "Error"), "" );
}

#if IUTEST_HAS_NOEXCEPT && 0

void Noexcept() IUTEST_CXX_NOEXCEPT_SPEC
{
    throw 1;
}

IUTEST(NoThrowFailure, Noexcept)
{
    IUTEST_ASSERT_FATAL_FAILURE( IUTEST_ASSERT_NO_THROW(Noexcept()), "" );
}

#endif

#endif

#ifdef UNICODE
int wmain(int argc, wchar_t* argv[])
#else
int main(int argc, char* argv[])
#endif
{
    IUTEST_INIT(&argc, argv);
    return IUTEST_RUN_ALL_TESTS();
}

<|endoftext|>


<commit_before>#include <node.h>
#include <nan.h>

#include "enums.h"

extern "C" {
#include <ocstack.h>
}

using namespace v8;

// The rest of this file is generated

void InitConstants(Handle<Object> exports) {

  // ocstackconfig.h: Stack configuration
  SET_CONSTANT_MEMBER(exports, Number, DEV_ADDR_SIZE_MAX);
  SET_CONSTANT_MEMBER(exports, Number, MAX_CB_TIMEOUT_SECONDS);
  SET_CONSTANT_MEMBER(exports, Number, MAX_CONTAINED_RESOURCES);
  SET_CONSTANT_MEMBER(exports, Number, MAX_HEADER_OPTION_DATA_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_HEADER_OPTIONS);
  SET_CONSTANT_MEMBER(exports, Number, MAX_MANUFACTURER_NAME_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_MANUFACTURER_URL_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_QUERY_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_REQUEST_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_RESPONSE_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_URI_LENGTH);

  // octypes.h: Definitions
  SET_CONSTANT_MEMBER(exports, Number, OC_DEFAULT_PRESENCE_TTL_SECONDS);
  SET_CONSTANT_MEMBER(exports, Number, OC_MAX_PRESENCE_TTL_SECONDS);
  SET_CONSTANT_MEMBER(exports, Number, OC_MULTICAST_PORT);
  SET_CONSTANT_MEMBER(exports, String, OC_EXPLICIT_DEVICE_DISCOVERY_URI);
  SET_CONSTANT_MEMBER(exports, String, OC_MULTICAST_DISCOVERY_URI);
  SET_CONSTANT_MEMBER(exports, String, OC_MULTICAST_IP);
  SET_CONSTANT_MEMBER(exports, String, OC_MULTICAST_PREFIX);
  SET_CONSTANT_MEMBER(exports, String, OC_PRESENCE_URI);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_CONTENT_TYPE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_DEVICE_ID);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_DEVICE_NAME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_FIRMWARE_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_FW_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HARDWARE_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HOSTING_PORT);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HOST_NAME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HREF);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_BATCH);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_DEFAULT);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_GROUP);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_LL);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MFG_DATE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MFG_NAME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MFG_URL);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MODEL_NUM);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_OBSERVABLE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_OC);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_OS_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PAYLOAD);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PLATFORM_ID);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PLATFORM_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PROPERTY);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_REPRESENTATION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_RESOURCE_TYPE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_RESOURCE_TYPE_PRESENCE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SECURE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SERVER_INSTANCE_ID);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SUPPORT_URL);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SYSTEM_TIME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_WELL_KNOWN_QUERY);
}
<commit_msg>Constants: Update to 809b1b1<commit_after>#include <node.h>
#include <nan.h>

#include "enums.h"

extern "C" {
#include <ocstack.h>
}

using namespace v8;

// The rest of this file is generated

void InitConstants(Handle<Object> exports) {

  // ocstackconfig.h: Stack configuration
  SET_CONSTANT_MEMBER(exports, Number, DEV_ADDR_SIZE_MAX);
  SET_CONSTANT_MEMBER(exports, Number, MAX_CB_TIMEOUT_SECONDS);
  SET_CONSTANT_MEMBER(exports, Number, MAX_CONTAINED_RESOURCES);
  SET_CONSTANT_MEMBER(exports, Number, MAX_HEADER_OPTION_DATA_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_HEADER_OPTIONS);
  SET_CONSTANT_MEMBER(exports, Number, MAX_MANUFACTURER_NAME_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_MANUFACTURER_URL_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_QUERY_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_REQUEST_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_RESPONSE_LENGTH);
  SET_CONSTANT_MEMBER(exports, Number, MAX_URI_LENGTH);

  // octypes.h: Definitions
  SET_CONSTANT_MEMBER(exports, Number, OC_DEFAULT_PRESENCE_TTL_SECONDS);
  SET_CONSTANT_MEMBER(exports, Number, OC_MAX_PRESENCE_TTL_SECONDS);
  SET_CONSTANT_MEMBER(exports, Number, OC_MULTICAST_PORT);
  SET_CONSTANT_MEMBER(exports, String, OC_DATA_MODEL_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_EXPLICIT_DEVICE_DISCOVERY_URI);
  SET_CONSTANT_MEMBER(exports, String, OC_MULTICAST_DISCOVERY_URI);
  SET_CONSTANT_MEMBER(exports, String, OC_MULTICAST_IP);
  SET_CONSTANT_MEMBER(exports, String, OC_MULTICAST_PREFIX);
  SET_CONSTANT_MEMBER(exports, String, OC_PRESENCE_URI);
  SET_CONSTANT_MEMBER(exports, String, OC_QUERY_SEPARATOR);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_CONTENT_TYPE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_DATA_MODEL_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_DEVICE_ID);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_DEVICE_NAME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_FIRMWARE_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_FW_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HARDWARE_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HOSTING_PORT);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HOST_NAME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_HREF);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_BATCH);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_DEFAULT);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_GROUP);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_INTERFACE_LL);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MFG_DATE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MFG_NAME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MFG_URL);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_MODEL_NUM);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_NONCE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_OBSERVABLE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_OC);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_OS_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PAYLOAD);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PLATFORM_ID);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PLATFORM_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_PROPERTY);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_REPRESENTATION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_RESOURCE_TYPE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_RESOURCE_TYPE_PRESENCE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SECURE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SERVER_INSTANCE_ID);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SPEC_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SUPPORT_URL);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_SYSTEM_TIME);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_TRIGGER);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_TRIGGER_CHANGE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_TRIGGER_CREATE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_TRIGGER_DELETE);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_TTL);
  SET_CONSTANT_MEMBER(exports, String, OC_RSRVD_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_SPEC_VERSION);
  SET_CONSTANT_MEMBER(exports, String, OC_WELL_KNOWN_QUERY);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <thrift/compiler/parse/lexer.h>

#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <algorithm>
#include <unordered_map>
#include <utility>

#include <thrift/compiler/diagnostic.h>

namespace apache {
namespace thrift {
namespace compiler {

namespace {

bool is_whitespace(char c) {
  return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}

bool is_letter(char c) {
  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}

bool is_bin_digit(char c) {
  return c == '0' || c == '1';
}
bool is_oct_digit(char c) {
  return c >= '0' && c <= '7';
}
bool is_dec_digit(char c) {
  return c >= '0' && c <= '9';
}
bool is_hex_digit(char c) {
  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
      (c >= 'A' && c <= 'F');
}

bool is_identifier_char(char c) {
  return is_letter(c) || is_dec_digit(c) || c == '_' || c == '.';
}

// Lexes a decimal constant of the form [0-9]+. Returns a pointer past the end
// if the constant has been lexed; `none` otherwise.
const char* lex_dec_literal(const char* p, const char* none = nullptr) {
  if (!is_dec_digit(*p)) {
    return none;
  }
  do {
    ++p;
  } while (is_dec_digit(*p));
  return p;
}

// Lexes a float exponent of the form [eE][+-]?[0-9]+. Returns a pointer past
// the end if the exponent has been lexed; `none` otherwise.
const char* lex_float_exponent(const char* p, const char* none = nullptr) {
  if (*p != 'e' && *p != 'E') {
    return none;
  }
  ++p; // Consume 'e' or 'E'.
  if (*p == '+' || *p == '-') {
    ++p; // Consume the sign.
  }
  return lex_dec_literal(p);
}

// Lexes a float constant in the form [0-9]+ followed by an optional exponent.
// Returns a pointer past the end if the constant has been lexed; nullptr
// otherwise.
const char* lex_float_literal(const char* p) {
  p = lex_dec_literal(p);
  return p ? lex_float_exponent(p, p) : nullptr;
}

const std::unordered_map<std::string, tok> keywords = {
    {"false", tok::bool_literal},
    {"true", tok::bool_literal},
    {"include", tok::kw_include},
    {"cpp_include", tok::kw_cpp_include},
    {"hs_include", tok::kw_hs_include},
    {"package", tok::kw_package},
    {"namespace", tok::kw_namespace},
    {"void", tok::kw_void},
    {"bool", tok::kw_bool},
    {"byte", tok::kw_byte},
    {"i16", tok::kw_i16},
    {"i32", tok::kw_i32},
    {"i64", tok::kw_i64},
    {"double", tok::kw_double},
    {"float", tok::kw_float},
    {"string", tok::kw_string},
    {"binary", tok::kw_binary},
    {"map", tok::kw_map},
    {"list", tok::kw_list},
    {"set", tok::kw_set},
    {"sink", tok::kw_sink},
    {"stream", tok::kw_stream},
    {"interaction", tok::kw_interaction},
    {"performs", tok::kw_performs},
    {"oneway", tok::kw_oneway},
    {"idempotent", tok::kw_idempotent},
    {"readonly", tok::kw_readonly},
    {"safe", tok::kw_safe},
    {"transient", tok::kw_transient},
    {"stateful", tok::kw_stateful},
    {"permanent", tok::kw_permanent},
    {"server", tok::kw_server},
    {"client", tok::kw_client},
    {"typedef", tok::kw_typedef},
    {"struct", tok::kw_struct},
    {"union", tok::kw_union},
    {"exception", tok::kw_exception},
    {"extends", tok::kw_extends},
    {"throws", tok::kw_throws},
    {"service", tok::kw_service},
    {"enum", tok::kw_enum},
    {"const", tok::kw_const},
    {"required", tok::kw_required},
    {"optional", tok::kw_optional},
};

} // namespace

lexer::lexer(source src, lex_handler& handler, diagnostics_engine& diags)
    : source_(src.text), start_(src.start), handler_(&handler), diags_(&diags) {
  ptr_ = source_.data();
  token_start_ = ptr_;
}

token lexer::make_int_literal(int offset, int base) {
  fmt::string_view text = token_text();
  errno = 0;
  char* end = nullptr;
  uint64_t val = strtoull(text.data() + offset, &end, base);
  assert(end == text.data() + text.size());
  return errno != ERANGE
      ? token::make_int_literal(token_source_range(), val)
      : report_error("integer constant {} is too large", text);
}

token lexer::make_float_literal() {
  fmt::string_view text = token_text();
  errno = 0;
  double val = strtod(std::string(text.data(), text.size()).c_str(), nullptr);
  if (errno == ERANGE) {
    if (val == 0) {
      return report_error(
          "magnitude of floating-point constant {} is too small", text);
    } else if (val == HUGE_VAL || val == -HUGE_VAL) {
      return report_error("floating-point constant {} is out of range", text);
    }
    // Allow subnormals.
  }
  return token::make_float_literal(token_source_range(), val);
}

template <typename... T>
token lexer::report_error(fmt::format_string<T...> msg, T&&... args) {
  diags_->report(
      location(token_start_),
      diagnostic_level::error,
      msg,
      std::forward<T>(args)...);
  return token(tok::error, token_source_range());
}

token lexer::unexpected_token() {
  return report_error("unexpected token in input: {}", token_text());
}

void lexer::skip_line_comment() {
  ptr_ = std::find(ptr_, end(), '\n');
}

bool lexer::lex_doc_comment() {
  assert(strncmp(ptr_, "///", 3) == 0);
  start_token();
  bool is_inline = ptr_[3] == '<';
  const char* prefix = ptr_;
  size_t prefix_size = is_inline ? 4 : 3;
  do {
    if (!is_inline && ptr_[3] == '/') {
      break;
    }
    ptr_ += prefix_size; // Skip "///" or "///<".
    skip_line_comment();
    while (is_whitespace(*ptr_)) {
      ++ptr_;
    }
  } while (strncmp(ptr_, prefix, prefix_size) == 0);
  if (!is_inline) {
    handler_->on_doc_comment(token_text(), location(ptr_));
  }
  return is_inline;
}

lexer::comment_lex_result lexer::lex_block_comment() {
  assert(strncmp(ptr_, "/*", 2) == 0);
  const char* p = ptr_ + 2; // Skip "/*".
  start_token();
  do {
    p = std::find(p, end(), '*');
    if (!*p) { // EOF while lexing a block comment.
      return comment_lex_result::unterminated;
    }
    ++p; // Skip '*'.
  } while (*p != '/');
  ptr_ = p + 1; // Skip '/'.
  if (token_start_[2] == '*') {
    if (token_start_[3] == '<') {
      return comment_lex_result::doc_comment;
    }
    // Ignore comments containing only '*'s.
    auto non_star = std::find_if(
        token_start_ + 2, ptr_ - 1, [](char c) { return c != '*'; });
    if (non_star != ptr_ - 1) {
      handler_->on_doc_comment(token_text(), location(ptr_));
    }
  }
  return comment_lex_result::skipped;
}

lexer::comment_lex_result lexer::lex_whitespace_or_comment() {
  for (;;) {
    switch (*ptr_) {
      case '\n':
      case ' ':
      case '\t':
      case '\r':
        ++ptr_;
        break;
      case '/':
        if (ptr_[1] == '/') {
          if (ptr_[2] == '/' && ptr_[3] != '/') {
            if (lex_doc_comment()) {
              return comment_lex_result::doc_comment;
            }
            continue;
          }
          ptr_ += 2; // Skip "//".
          skip_line_comment();
          break;
        }
        if (ptr_[1] == '*') {
          comment_lex_result res = lex_block_comment();
          if (res != comment_lex_result::skipped) {
            return res;
          }
          continue;
        }
        return comment_lex_result::skipped;
      case '#':
        ++ptr_;
        skip_line_comment();
        break;
      default:
        return comment_lex_result::skipped;
    }
  }
}

token lexer::get_next_token() {
  if (lex_whitespace_or_comment() == comment_lex_result::doc_comment) {
    return token::make_inline_doc(token_source_range(), token_text());
  }

  start_token();

  char c = *ptr_++;
  if (is_letter(c) || c == '_') {
    // Lex an identifier or a keyword.
    while (is_identifier_char(*ptr_)) {
      ++ptr_;
    }
    auto text = token_text();
    auto it = keywords.find(std::string(text.data(), text.size()));
    if (it != keywords.end()) {
      return it->second == tok::bool_literal
          ? token::make_bool_literal(token_source_range(), it->first == "true")
          : token(it->second, token_source_range());
    }
    return token::make_identifier(token_source_range(), text);
  } else if (c == '.') {
    if (const char* p = lex_float_literal(ptr_)) {
      ptr_ = p;
      return make_float_literal();
    }
  } else if (is_dec_digit(c)) {
    if (c == '0') {
      switch (*ptr_) {
        case 'x':
        case 'X':
          // Lex a hexadecimal constant.
          if (!is_hex_digit(ptr_[1])) {
            return unexpected_token();
          }
          ptr_ += 2;
          while (is_hex_digit(*ptr_)) {
            ++ptr_;
          }
          return make_int_literal(2, 16);
        case 'b':
        case 'B':
          // Lex a binary constant.
          if (!is_bin_digit(ptr_[1])) {
            return unexpected_token();
          }
          ptr_ += 2;
          while (is_bin_digit(*ptr_)) {
            ++ptr_;
          }
          return make_int_literal(2, 2);
      }
    }
    // Lex a decimal, octal or floating-point constant.
    ptr_ = lex_dec_literal(ptr_, ptr_);
    switch (*ptr_) {
      case '.':
        if (const char* p = lex_float_literal(ptr_ + 1)) {
          ptr_ = p;
          return make_float_literal();
        }
        break;
      case 'e':
      case 'E':
        if (const char* p = lex_float_exponent(ptr_)) {
          ptr_ = p;
          return make_float_literal();
        }
        break;
    }
    if (c != '0') {
      // Lex a decimal constant.
      return make_int_literal(0, 10);
    }
    // Lex an octal constant.
    const char* p = std::find_if(
        token_start_, ptr_, [](char c) { return !is_oct_digit(c); });
    if (p != ptr_) {
      return unexpected_token();
    }
    return ptr_ - token_start_ != 1
        ? make_int_literal(1, 8)
        : token::make_int_literal(token_source_range(), 0);
  } else if (c == '"' || c == '\'') {
    // Lex a string literal.
    const char* p = std::find(ptr_, end(), c);
    if (*p) {
      ptr_ = p + 1;
      const char* begin = token_start_ + 1;
      return token::make_string_literal(
          token_source_range(), {begin, static_cast<size_t>(p - begin)});
    }
  } else if (!c && ptr_ > end()) {
    --ptr_; // Put '\0' back in case get_next_token() is called again.
    return token(tok::eof, token_source_range());
  }

  // Lex operators and punctuators.
  auto kind = detail::to_tok(c);
  return kind != tok::error ? token(kind, token_source_range())
                            : unexpected_token();
}

} // namespace compiler
} // namespace thrift
} // namespace apache
<commit_msg>Make lexing of literals more robust<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <thrift/compiler/parse/lexer.h>

#include <assert.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#include <algorithm>
#include <unordered_map>
#include <utility>

#include <thrift/compiler/diagnostic.h>

namespace apache {
namespace thrift {
namespace compiler {

namespace {

bool is_whitespace(char c) {
  return c == ' ' || c == '\t' || c == '\r' || c == '\n';
}

bool is_letter(char c) {
  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}

bool is_bin_digit(char c) {
  return c == '0' || c == '1';
}
bool is_oct_digit(char c) {
  return c >= '0' && c <= '7';
}
bool is_dec_digit(char c) {
  return c >= '0' && c <= '9';
}
bool is_hex_digit(char c) {
  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
      (c >= 'A' && c <= 'F');
}

bool is_identifier_char(char c) {
  return is_letter(c) || is_dec_digit(c) || c == '_' || c == '.';
}

// Lexes a decimal constant of the form [0-9]+. Returns a pointer past the end
// if the constant has been lexed; `none` otherwise.
const char* lex_dec_literal(const char* p, const char* none = nullptr) {
  if (!is_dec_digit(*p)) {
    return none;
  }
  do {
    ++p;
  } while (is_dec_digit(*p));
  return p;
}

// Lexes a float exponent of the form [eE][+-]?[0-9]+. Returns a pointer past
// the end if the exponent has been lexed; `none` otherwise.
const char* lex_float_exponent(const char* p, const char* none = nullptr) {
  if (*p != 'e' && *p != 'E') {
    return none;
  }
  ++p; // Consume 'e' or 'E'.
  if (*p == '+' || *p == '-') {
    ++p; // Consume the sign.
  }
  return lex_dec_literal(p);
}

// Lexes a float constant in the form [0-9]+ followed by an optional exponent.
// Returns a pointer past the end if the constant has been lexed; nullptr
// otherwise.
const char* lex_float_literal(const char* p) {
  p = lex_dec_literal(p);
  return p ? lex_float_exponent(p, p) : nullptr;
}

const std::unordered_map<std::string, tok> keywords = {
    {"false", tok::bool_literal},
    {"true", tok::bool_literal},
    {"include", tok::kw_include},
    {"cpp_include", tok::kw_cpp_include},
    {"hs_include", tok::kw_hs_include},
    {"package", tok::kw_package},
    {"namespace", tok::kw_namespace},
    {"void", tok::kw_void},
    {"bool", tok::kw_bool},
    {"byte", tok::kw_byte},
    {"i16", tok::kw_i16},
    {"i32", tok::kw_i32},
    {"i64", tok::kw_i64},
    {"double", tok::kw_double},
    {"float", tok::kw_float},
    {"string", tok::kw_string},
    {"binary", tok::kw_binary},
    {"map", tok::kw_map},
    {"list", tok::kw_list},
    {"set", tok::kw_set},
    {"sink", tok::kw_sink},
    {"stream", tok::kw_stream},
    {"interaction", tok::kw_interaction},
    {"performs", tok::kw_performs},
    {"oneway", tok::kw_oneway},
    {"idempotent", tok::kw_idempotent},
    {"readonly", tok::kw_readonly},
    {"safe", tok::kw_safe},
    {"transient", tok::kw_transient},
    {"stateful", tok::kw_stateful},
    {"permanent", tok::kw_permanent},
    {"server", tok::kw_server},
    {"client", tok::kw_client},
    {"typedef", tok::kw_typedef},
    {"struct", tok::kw_struct},
    {"union", tok::kw_union},
    {"exception", tok::kw_exception},
    {"extends", tok::kw_extends},
    {"throws", tok::kw_throws},
    {"service", tok::kw_service},
    {"enum", tok::kw_enum},
    {"const", tok::kw_const},
    {"required", tok::kw_required},
    {"optional", tok::kw_optional},
};

} // namespace

lexer::lexer(source src, lex_handler& handler, diagnostics_engine& diags)
    : source_(src.text), start_(src.start), handler_(&handler), diags_(&diags) {
  ptr_ = source_.data();
  token_start_ = ptr_;
}

token lexer::make_int_literal(int offset, int base) {
  fmt::string_view text = token_text();
  errno = 0;
  char* end = nullptr;
  uint64_t val = strtoull(text.data() + offset, &end, base);
  if (end != text.data() + text.size()) {
    return report_error("internal error when lexing an int literal");
  }
  return errno != ERANGE
      ? token::make_int_literal(token_source_range(), val)
      : report_error("integer constant {} is too large", text);
}

token lexer::make_float_literal() {
  fmt::string_view text = token_text();
  errno = 0;
  char* end = nullptr;
  double val = strtod(text.data(), &end);
  if (errno == ERANGE) {
    if (val == 0) {
      return report_error(
          "magnitude of floating-point constant {} is too small", text);
    } else if (val == HUGE_VAL || val == -HUGE_VAL) {
      return report_error("floating-point constant {} is out of range", text);
    }
    // Allow subnormals.
  }
  if (end != text.data() + text.size()) {
    return report_error("internal error when lexing a float literal");
  }
  return token::make_float_literal(token_source_range(), val);
}

template <typename... T>
token lexer::report_error(fmt::format_string<T...> msg, T&&... args) {
  diags_->report(
      location(token_start_),
      diagnostic_level::error,
      msg,
      std::forward<T>(args)...);
  return token(tok::error, token_source_range());
}

token lexer::unexpected_token() {
  return report_error("unexpected token in input: {}", token_text());
}

void lexer::skip_line_comment() {
  ptr_ = std::find(ptr_, end(), '\n');
}

bool lexer::lex_doc_comment() {
  assert(strncmp(ptr_, "///", 3) == 0);
  start_token();
  bool is_inline = ptr_[3] == '<';
  const char* prefix = ptr_;
  size_t prefix_size = is_inline ? 4 : 3;
  do {
    if (!is_inline && ptr_[3] == '/') {
      break;
    }
    ptr_ += prefix_size; // Skip "///" or "///<".
    skip_line_comment();
    while (is_whitespace(*ptr_)) {
      ++ptr_;
    }
  } while (strncmp(ptr_, prefix, prefix_size) == 0);
  if (!is_inline) {
    handler_->on_doc_comment(token_text(), location(ptr_));
  }
  return is_inline;
}

lexer::comment_lex_result lexer::lex_block_comment() {
  assert(strncmp(ptr_, "/*", 2) == 0);
  const char* p = ptr_ + 2; // Skip "/*".
  start_token();
  do {
    p = std::find(p, end(), '*');
    if (!*p) { // EOF while lexing a block comment.
      return comment_lex_result::unterminated;
    }
    ++p; // Skip '*'.
  } while (*p != '/');
  ptr_ = p + 1; // Skip '/'.
  if (token_start_[2] == '*') {
    if (token_start_[3] == '<') {
      return comment_lex_result::doc_comment;
    }
    // Ignore comments containing only '*'s.
    auto non_star = std::find_if(
        token_start_ + 2, ptr_ - 1, [](char c) { return c != '*'; });
    if (non_star != ptr_ - 1) {
      handler_->on_doc_comment(token_text(), location(ptr_));
    }
  }
  return comment_lex_result::skipped;
}

lexer::comment_lex_result lexer::lex_whitespace_or_comment() {
  for (;;) {
    switch (*ptr_) {
      case '\n':
      case ' ':
      case '\t':
      case '\r':
        ++ptr_;
        break;
      case '/':
        if (ptr_[1] == '/') {
          if (ptr_[2] == '/' && ptr_[3] != '/') {
            if (lex_doc_comment()) {
              return comment_lex_result::doc_comment;
            }
            continue;
          }
          ptr_ += 2; // Skip "//".
          skip_line_comment();
          break;
        }
        if (ptr_[1] == '*') {
          comment_lex_result res = lex_block_comment();
          if (res != comment_lex_result::skipped) {
            return res;
          }
          continue;
        }
        return comment_lex_result::skipped;
      case '#':
        ++ptr_;
        skip_line_comment();
        break;
      default:
        return comment_lex_result::skipped;
    }
  }
}

token lexer::get_next_token() {
  if (lex_whitespace_or_comment() == comment_lex_result::doc_comment) {
    return token::make_inline_doc(token_source_range(), token_text());
  }

  start_token();

  char c = *ptr_++;
  if (is_letter(c) || c == '_') {
    // Lex an identifier or a keyword.
    while (is_identifier_char(*ptr_)) {
      ++ptr_;
    }
    auto text = token_text();
    auto it = keywords.find(std::string(text.data(), text.size()));
    if (it != keywords.end()) {
      return it->second == tok::bool_literal
          ? token::make_bool_literal(token_source_range(), it->first == "true")
          : token(it->second, token_source_range());
    }
    return token::make_identifier(token_source_range(), text);
  } else if (c == '.') {
    if (const char* p = lex_float_literal(ptr_)) {
      ptr_ = p;
      return make_float_literal();
    }
  } else if (is_dec_digit(c)) {
    if (c == '0') {
      switch (*ptr_) {
        case 'x':
        case 'X':
          // Lex a hexadecimal constant.
          if (!is_hex_digit(ptr_[1])) {
            return unexpected_token();
          }
          ptr_ += 2;
          while (is_hex_digit(*ptr_)) {
            ++ptr_;
          }
          return make_int_literal(2, 16);
        case 'b':
        case 'B':
          // Lex a binary constant.
          if (!is_bin_digit(ptr_[1])) {
            return unexpected_token();
          }
          ptr_ += 2;
          while (is_bin_digit(*ptr_)) {
            ++ptr_;
          }
          return make_int_literal(2, 2);
      }
    }
    // Lex a decimal, octal or floating-point constant.
    ptr_ = lex_dec_literal(ptr_, ptr_);
    switch (*ptr_) {
      case '.':
        if (const char* p = lex_float_literal(ptr_ + 1)) {
          ptr_ = p;
          return make_float_literal();
        }
        break;
      case 'e':
      case 'E':
        if (const char* p = lex_float_exponent(ptr_)) {
          ptr_ = p;
          return make_float_literal();
        }
        break;
    }
    if (c != '0') {
      // Lex a decimal constant.
      return make_int_literal(0, 10);
    }
    // Lex an octal constant.
    const char* p = std::find_if(
        token_start_, ptr_, [](char c) { return !is_oct_digit(c); });
    if (p != ptr_) {
      return unexpected_token();
    }
    return ptr_ - token_start_ != 1
        ? make_int_literal(1, 8)
        : token::make_int_literal(token_source_range(), 0);
  } else if (c == '"' || c == '\'') {
    // Lex a string literal.
    const char* p = std::find(ptr_, end(), c);
    if (*p) {
      ptr_ = p + 1;
      const char* begin = token_start_ + 1;
      return token::make_string_literal(
          token_source_range(), {begin, static_cast<size_t>(p - begin)});
    }
  } else if (!c && ptr_ > end()) {
    --ptr_; // Put '\0' back in case get_next_token() is called again.
    return token(tok::eof, token_source_range());
  }

  // Lex operators and punctuators.
  auto kind = detail::to_tok(c);
  return kind != tok::error ? token(kind, token_source_range())
                            : unexpected_token();
}

} // namespace compiler
} // namespace thrift
} // namespace apache
<|endoftext|>