<commit_before>#pragma once
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
 * Modified by ScyllaDB
 * Copyright (C) 2015 ScyllaDB
 */

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

#include <stdint.h>
#include <assert.h>

#include <memory>
#include <chrono>
#include <random>
#include <limits>

#include "UUID.hh"
#include "db_clock.hh"

namespace utils {

/**
 * The goods are here: www.ietf.org/rfc/rfc4122.txt.
 */
class UUID_gen
{
private:
    // A grand day! millis at 00:00:00.000 15 Oct 1582.
    static constexpr int64_t START_EPOCH = -12219292800000L;
    static thread_local const int64_t clock_seq_and_node;

    /*
     * The min and max possible lsb for a UUID.
     * Note that his is not 0 and all 1's because Cassandra TimeUUIDType
     * compares the lsb parts as a signed byte array comparison. So the min
     * value is 8 times -128 and the max is 8 times +127.
     *
     * Note that we ignore the uuid variant (namely, MIN_CLOCK_SEQ_AND_NODE
     * have variant 2 as it should, but MAX_CLOCK_SEQ_AND_NODE have variant 0).
     * I don't think that has any practical consequence and is more robust in
     * case someone provides a UUID with a broken variant.
     */
    static constexpr int64_t MIN_CLOCK_SEQ_AND_NODE = 0x8080808080808080L;
    static constexpr int64_t MAX_CLOCK_SEQ_AND_NODE = 0x7f7f7f7f7f7f7f7fL;

    // placement of this singleton is important.  It needs to be instantiated *AFTER* the other statics.
    static thread_local const std::unique_ptr<UUID_gen> instance;

    uint64_t last_nanos = 0;

    UUID_gen()
    {
        // make sure someone didn't whack the clockSeqAndNode by changing the order of instantiation.
        assert(clock_seq_and_node != 0);
    }

public:
    /**
     * Creates a type 1 UUID (time-based UUID).
     *
     * @return a UUID instance
     */
    static UUID get_time_UUID()
    {
        auto uuid = UUID(instance->create_time_safe(), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * Creates a type 1 UUID (time-based UUID) with the timestamp of @param when, in milliseconds.
     *
     * @return a UUID instance
     */
    static UUID get_time_UUID(int64_t when)
    {
        auto uuid = UUID(create_time(from_unix_timestamp(when)), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * Creates a type 1 UUID (time-based UUID) with the wall clock time point @param tp.
     *
     * @return a UUID instance
     */
    static UUID get_time_UUID(std::chrono::system_clock::time_point tp)
    {
        using namespace std::chrono;
        // "nanos" needs to be in 100ns intervals since the adoption of the Gregorian calendar in the West.
        uint64_t nanos = duration_cast<nanoseconds>(tp.time_since_epoch()).count() / 100;
        nanos -= (10000ULL * START_EPOCH);
        auto uuid = UUID(create_time(nanos), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }

    static UUID get_time_UUID(int64_t when, int64_t clock_seq_and_node)
    {
        auto uuid = UUID(create_time(from_unix_timestamp(when)), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }
    /**
     * Similar to get_time_UUID, but randomize the clock and sequence.
     * If you can guarantee that the when_in_micros() argument is unique for
     * every call, then you should prefer get_time_UUID_from_micros() which is faster. If you can't
     * guarantee this however, this method will ensure the returned UUID are still unique (across calls)
     * through randomization.
     *
     * @param when_in_micros a unix time in microseconds.
     * @return a new UUID 'id' such that micros_timestamp(id) == when_in_micros. The UUID returned
     * by different calls will be unique even if when_in_micros is not.
     */
    static UUID get_random_time_UUID_from_micros(int64_t when_in_micros) {
        static thread_local std::mt19937_64 rand_gen(std::random_device().operator()());
        static thread_local std::uniform_int_distribution<int64_t> rand_dist(std::numeric_limits<int64_t>::min());

        int64_t when_in_millis = when_in_micros / 1000;
        int64_t nanos = (when_in_micros - (when_in_millis * 1000)) * 10;

        auto uuid = UUID(create_time(from_unix_timestamp(when_in_millis) + nanos), rand_dist(rand_gen));
        assert(uuid.is_timestamp());
        return uuid;
    }

    /** creates uuid from raw bytes. */
    static UUID get_UUID(bytes raw) {
        assert(raw.size() == 16);
        return get_UUID(raw.begin());
    }

    /** creates uuid from raw bytes. src must point to a region of 16 bytes*/
    static UUID get_UUID(int8_t* src) {
        struct tmp { uint64_t msb, lsb; } t;
        std::copy(src, src + 16, reinterpret_cast<char*>(&t));
        return UUID(net::ntoh(t.msb), net::ntoh(t.lsb));
    }

    /**
     * Creates a type 3 (name based) UUID based on the specified byte array.
     */
    static UUID get_name_UUID(bytes_view b);
    static UUID get_name_UUID(sstring_view str);
    static UUID get_name_UUID(const unsigned char* s, size_t len);

    /** decomposes a uuid into raw bytes. */
    static std::array<int8_t, 16> decompose(const UUID& uuid)
    {
        uint64_t most = uuid.get_most_significant_bits();
        uint64_t least = uuid.get_least_significant_bits();
        std::array<int8_t, 16> b;
        for (int i = 0; i < 8; i++)
        {
            b[i] = (char)(most >> ((7-i) * 8));
            b[8+i] = (char)(least >> ((7-i) * 8));
        }
        return b;
    }

    /**
     * Returns a 16 byte representation of a type 1 UUID (a time-based UUID),
     * based on the current system time.
     *
     * @return a type 1 UUID represented as a byte[]
     */
    static std::array<int8_t, 16> get_time_UUID_bytes()
    {
        return create_time_UUID_bytes(instance->create_time_safe());
    }

    /**
     * Returns the smaller possible type 1 UUID having the provided timestamp.
     *
     * Warning: this method should only be used for querying as this
     * doesn't at all guarantee the uniqueness of the resulting UUID.
     */
    static UUID min_time_UUID(int64_t timestamp)
    {
        auto uuid = UUID(create_time(from_unix_timestamp(timestamp)), MIN_CLOCK_SEQ_AND_NODE);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * Returns the biggest possible type 1 UUID having the provided timestamp.
     *
     * Warning: this method should only be used for querying as this
     * doesn't at all guarantee the uniqueness of the resulting UUID.
     */
    static UUID max_time_UUID(int64_t timestamp)
    {
        // unix timestamp are milliseconds precision, uuid timestamp are 100's
        // nanoseconds precision. If we ask for the biggest uuid have unix
        // timestamp 1ms, then we should not extend 100's nanoseconds
        // precision by taking 10000, but rather 19999.
        int64_t uuid_tstamp = from_unix_timestamp(timestamp + 1) - 1;
        auto uuid = UUID(create_time(uuid_tstamp), MAX_CLOCK_SEQ_AND_NODE);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * @param uuid
     * @return milliseconds since Unix epoch
     */
    static int64_t unix_timestamp(UUID uuid)
    {
        return (uuid.timestamp() / 10000) + START_EPOCH;
    }

    /**
     * @param uuid
     * @return seconds since Unix epoch
     */
    static std::chrono::seconds unix_timestamp_in_sec(UUID uuid)
    {
        using namespace std::chrono;
        return duration_cast<seconds>(static_cast<milliseconds>(unix_timestamp(uuid)));
    }

    /**
     * @param uuid
     * @return microseconds since Unix epoch
     */
    static int64_t micros_timestamp(UUID uuid)
    {
        return (uuid.timestamp() / 10) + START_EPOCH * 1000;
    }

private:
    /**
     * @param timestamp milliseconds since Unix epoch
     * @return
     */
    static int64_t from_unix_timestamp(int64_t timestamp) {
        return (timestamp - START_EPOCH) * 10000;
    }

public:
    /**
     * Converts a 100-nanoseconds precision timestamp into the 16 byte representation
     * of a type 1 UUID (a time-based UUID).
     *
     * To specify a 100-nanoseconds precision timestamp, one should provide a milliseconds timestamp and
     * a number 0 <= n < 10000 such that n*100 is the number of nanoseconds within that millisecond.
     *
     *
Warning: This method is not guaranteed to return unique UUIDs; Multiple
     * invocations using identical timestamps will result in identical UUIDs.

     *
     * @return a type 1 UUID represented as a byte[]
     */
    static std::array<int8_t, 16> get_time_UUID_bytes(int64_t time_millis, int nanos)
    {
#if 0
        if (nanos >= 10000)
            throw new IllegalArgumentException();
#endif
        return create_time_UUID_bytes(instance->create_time_unsafe(time_millis, nanos));
    }

private:
    static std::array<int8_t, 16> create_time_UUID_bytes(uint64_t msb)
    {
        uint64_t lsb = clock_seq_and_node;
        std::array<int8_t, 16> uuid_bytes;

        for (int i = 0; i < 8; i++)
            uuid_bytes[i] = (int8_t) (msb >> 8 * (7 - i));

        for (int i = 8; i < 16; i++)
            uuid_bytes[i] = (int8_t) (lsb >> 8 * (7 - (i - 8)));

        return uuid_bytes;
    }

public:
    /**
     * Returns a milliseconds-since-epoch value for a type-1 UUID.
     *
     * @param uuid a type-1 (time-based) UUID
     * @return the number of milliseconds since the unix epoch
     * @throws IllegalArgumentException if the UUID is not version 1
     */
    static int64_t get_adjusted_timestamp(UUID uuid)
    {
#if 0
        if (uuid.version() != 1)
            throw new IllegalArgumentException("incompatible with uuid version: "+uuid.version());
#endif
        return (uuid.timestamp() / 10000) + START_EPOCH;
    }

    static uint64_t make_nanos_since(int64_t millis) {
        return (static_cast<uint64_t>(millis) - static_cast<uint64_t>(START_EPOCH)) * 10000;
    }

private:

    // needs to return two different values for the same when.
    // we can generate at most 10k UUIDs per ms.
    // NOTE: In the original Java code this function was "synchronized". This isn't
    // needed if we assume our code will run on just one CPU.
    int64_t create_time_safe()
    {
        using namespace std::chrono;
        int64_t millis = duration_cast<milliseconds>(
                system_clock::now().time_since_epoch()).count();
        uint64_t nanos_since = make_nanos_since(millis);
        if (nanos_since > last_nanos)
            last_nanos = nanos_since;
        else
            nanos_since = ++last_nanos;

        return create_time(nanos_since);
    }

    int64_t create_time_unsafe(int64_t when, int nanos)
    {
        uint64_t nanos_since = make_nanos_since(when) + static_cast<uint64_t>(static_cast<int64_t>(nanos));
        return create_time(nanos_since);
    }

    static int64_t create_time(uint64_t nanos_since)
    {
        uint64_t msb = 0L;
        msb |= (0x00000000ffffffffL & nanos_since) << 32;
        msb |= (0x0000ffff00000000UL & nanos_since) >> 16;
        msb |= (0xffff000000000000UL & nanos_since) >> 48;
        msb |= 0x0000000000001000L; // sets the version to 1.
        return msb;
    }
};

// for the curious, here is how I generated START_EPOCH
//        Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
//        c.set(Calendar.YEAR, 1582);
//        c.set(Calendar.MONTH, Calendar.OCTOBER);
//        c.set(Calendar.DAY_OF_MONTH, 15);
//        c.set(Calendar.HOUR_OF_DAY, 0);
//        c.set(Calendar.MINUTE, 0);
//        c.set(Calendar.SECOND, 0);
//        c.set(Calendar.MILLISECOND, 0);
//        long START_EPOCH = c.getTimeInMillis();

} // namespace utils
<commit_msg>utils: UUID: create_time assert nanos_since validity<commit_after>#pragma once
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
 * Modified by ScyllaDB
 * Copyright (C) 2015 ScyllaDB
 */

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

#include <stdint.h>
#include <assert.h>

#include <memory>
#include <chrono>
#include <random>
#include <limits>

#include "UUID.hh"
#include "db_clock.hh"

namespace utils {

/**
 * The goods are here: www.ietf.org/rfc/rfc4122.txt.
 */
class UUID_gen
{
private:
    // A grand day! millis at 00:00:00.000 15 Oct 1582.
    static constexpr int64_t START_EPOCH = -12219292800000L;
    static thread_local const int64_t clock_seq_and_node;

    /*
     * The min and max possible lsb for a UUID.
     * Note that his is not 0 and all 1's because Cassandra TimeUUIDType
     * compares the lsb parts as a signed byte array comparison. So the min
     * value is 8 times -128 and the max is 8 times +127.
     *
     * Note that we ignore the uuid variant (namely, MIN_CLOCK_SEQ_AND_NODE
     * have variant 2 as it should, but MAX_CLOCK_SEQ_AND_NODE have variant 0).
     * I don't think that has any practical consequence and is more robust in
     * case someone provides a UUID with a broken variant.
     */
    static constexpr int64_t MIN_CLOCK_SEQ_AND_NODE = 0x8080808080808080L;
    static constexpr int64_t MAX_CLOCK_SEQ_AND_NODE = 0x7f7f7f7f7f7f7f7fL;

    // placement of this singleton is important.  It needs to be instantiated *AFTER* the other statics.
    static thread_local const std::unique_ptr<UUID_gen> instance;

    uint64_t last_nanos = 0;

    UUID_gen()
    {
        // make sure someone didn't whack the clockSeqAndNode by changing the order of instantiation.
        assert(clock_seq_and_node != 0);
    }

public:
    /**
     * Creates a type 1 UUID (time-based UUID).
     *
     * @return a UUID instance
     */
    static UUID get_time_UUID()
    {
        auto uuid = UUID(instance->create_time_safe(), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * Creates a type 1 UUID (time-based UUID) with the timestamp of @param when, in milliseconds.
     *
     * @return a UUID instance
     */
    static UUID get_time_UUID(int64_t when)
    {
        auto uuid = UUID(create_time(from_unix_timestamp(when)), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * Creates a type 1 UUID (time-based UUID) with the wall clock time point @param tp.
     *
     * @return a UUID instance
     */
    static UUID get_time_UUID(std::chrono::system_clock::time_point tp)
    {
        using namespace std::chrono;
        // "nanos" needs to be in 100ns intervals since the adoption of the Gregorian calendar in the West.
        uint64_t nanos = duration_cast<nanoseconds>(tp.time_since_epoch()).count() / 100;
        nanos -= (10000ULL * START_EPOCH);
        auto uuid = UUID(create_time(nanos), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }

    static UUID get_time_UUID(int64_t when, int64_t clock_seq_and_node)
    {
        auto uuid = UUID(create_time(from_unix_timestamp(when)), clock_seq_and_node);
        assert(uuid.is_timestamp());
        return uuid;
    }
    /**
     * Similar to get_time_UUID, but randomize the clock and sequence.
     * If you can guarantee that the when_in_micros() argument is unique for
     * every call, then you should prefer get_time_UUID_from_micros() which is faster. If you can't
     * guarantee this however, this method will ensure the returned UUID are still unique (across calls)
     * through randomization.
     *
     * @param when_in_micros a unix time in microseconds.
     * @return a new UUID 'id' such that micros_timestamp(id) == when_in_micros. The UUID returned
     * by different calls will be unique even if when_in_micros is not.
     */
    static UUID get_random_time_UUID_from_micros(int64_t when_in_micros) {
        static thread_local std::mt19937_64 rand_gen(std::random_device().operator()());
        static thread_local std::uniform_int_distribution<int64_t> rand_dist(std::numeric_limits<int64_t>::min());

        int64_t when_in_millis = when_in_micros / 1000;
        int64_t nanos = (when_in_micros - (when_in_millis * 1000)) * 10;

        auto uuid = UUID(create_time(from_unix_timestamp(when_in_millis) + nanos), rand_dist(rand_gen));
        assert(uuid.is_timestamp());
        return uuid;
    }

    /** creates uuid from raw bytes. */
    static UUID get_UUID(bytes raw) {
        assert(raw.size() == 16);
        return get_UUID(raw.begin());
    }

    /** creates uuid from raw bytes. src must point to a region of 16 bytes*/
    static UUID get_UUID(int8_t* src) {
        struct tmp { uint64_t msb, lsb; } t;
        std::copy(src, src + 16, reinterpret_cast<char*>(&t));
        return UUID(net::ntoh(t.msb), net::ntoh(t.lsb));
    }

    /**
     * Creates a type 3 (name based) UUID based on the specified byte array.
     */
    static UUID get_name_UUID(bytes_view b);
    static UUID get_name_UUID(sstring_view str);
    static UUID get_name_UUID(const unsigned char* s, size_t len);

    /** decomposes a uuid into raw bytes. */
    static std::array<int8_t, 16> decompose(const UUID& uuid)
    {
        uint64_t most = uuid.get_most_significant_bits();
        uint64_t least = uuid.get_least_significant_bits();
        std::array<int8_t, 16> b;
        for (int i = 0; i < 8; i++)
        {
            b[i] = (char)(most >> ((7-i) * 8));
            b[8+i] = (char)(least >> ((7-i) * 8));
        }
        return b;
    }

    /**
     * Returns a 16 byte representation of a type 1 UUID (a time-based UUID),
     * based on the current system time.
     *
     * @return a type 1 UUID represented as a byte[]
     */
    static std::array<int8_t, 16> get_time_UUID_bytes()
    {
        return create_time_UUID_bytes(instance->create_time_safe());
    }

    /**
     * Returns the smaller possible type 1 UUID having the provided timestamp.
     *
     * Warning: this method should only be used for querying as this
     * doesn't at all guarantee the uniqueness of the resulting UUID.
     */
    static UUID min_time_UUID(int64_t timestamp)
    {
        auto uuid = UUID(create_time(from_unix_timestamp(timestamp)), MIN_CLOCK_SEQ_AND_NODE);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * Returns the biggest possible type 1 UUID having the provided timestamp.
     *
     * Warning: this method should only be used for querying as this
     * doesn't at all guarantee the uniqueness of the resulting UUID.
     */
    static UUID max_time_UUID(int64_t timestamp)
    {
        // unix timestamp are milliseconds precision, uuid timestamp are 100's
        // nanoseconds precision. If we ask for the biggest uuid have unix
        // timestamp 1ms, then we should not extend 100's nanoseconds
        // precision by taking 10000, but rather 19999.
        int64_t uuid_tstamp = from_unix_timestamp(timestamp + 1) - 1;
        auto uuid = UUID(create_time(uuid_tstamp), MAX_CLOCK_SEQ_AND_NODE);
        assert(uuid.is_timestamp());
        return uuid;
    }

    /**
     * @param uuid
     * @return milliseconds since Unix epoch
     */
    static int64_t unix_timestamp(UUID uuid)
    {
        return (uuid.timestamp() / 10000) + START_EPOCH;
    }

    /**
     * @param uuid
     * @return seconds since Unix epoch
     */
    static std::chrono::seconds unix_timestamp_in_sec(UUID uuid)
    {
        using namespace std::chrono;
        return duration_cast<seconds>(static_cast<milliseconds>(unix_timestamp(uuid)));
    }

    /**
     * @param uuid
     * @return microseconds since Unix epoch
     */
    static int64_t micros_timestamp(UUID uuid)
    {
        return (uuid.timestamp() / 10) + START_EPOCH * 1000;
    }

private:
    /**
     * @param timestamp milliseconds since Unix epoch
     * @return
     */
    static int64_t from_unix_timestamp(int64_t timestamp) {
        return (timestamp - START_EPOCH) * 10000;
    }

public:
    /**
     * Converts a 100-nanoseconds precision timestamp into the 16 byte representation
     * of a type 1 UUID (a time-based UUID).
     *
     * To specify a 100-nanoseconds precision timestamp, one should provide a milliseconds timestamp and
     * a number 0 <= n < 10000 such that n*100 is the number of nanoseconds within that millisecond.
     *
     *
Warning: This method is not guaranteed to return unique UUIDs; Multiple
     * invocations using identical timestamps will result in identical UUIDs.

     *
     * @return a type 1 UUID represented as a byte[]
     */
    static std::array<int8_t, 16> get_time_UUID_bytes(int64_t time_millis, int nanos)
    {
#if 0
        if (nanos >= 10000)
            throw new IllegalArgumentException();
#endif
        return create_time_UUID_bytes(instance->create_time_unsafe(time_millis, nanos));
    }

private:
    static std::array<int8_t, 16> create_time_UUID_bytes(uint64_t msb)
    {
        uint64_t lsb = clock_seq_and_node;
        std::array<int8_t, 16> uuid_bytes;

        for (int i = 0; i < 8; i++)
            uuid_bytes[i] = (int8_t) (msb >> 8 * (7 - i));

        for (int i = 8; i < 16; i++)
            uuid_bytes[i] = (int8_t) (lsb >> 8 * (7 - (i - 8)));

        return uuid_bytes;
    }

public:
    /**
     * Returns a milliseconds-since-epoch value for a type-1 UUID.
     *
     * @param uuid a type-1 (time-based) UUID
     * @return the number of milliseconds since the unix epoch
     * @throws IllegalArgumentException if the UUID is not version 1
     */
    static int64_t get_adjusted_timestamp(UUID uuid)
    {
#if 0
        if (uuid.version() != 1)
            throw new IllegalArgumentException("incompatible with uuid version: "+uuid.version());
#endif
        return (uuid.timestamp() / 10000) + START_EPOCH;
    }

    static uint64_t make_nanos_since(int64_t millis) {
        return (static_cast<uint64_t>(millis) - static_cast<uint64_t>(START_EPOCH)) * 10000;
    }

    // nanos_since must fit in 60 bits
    static bool is_valid_nanos_since(uint64_t nanos_since) {
        return !(0xf000000000000000UL & nanos_since);
    }

private:

    // needs to return two different values for the same when.
    // we can generate at most 10k UUIDs per ms.
    // NOTE: In the original Java code this function was "synchronized". This isn't
    // needed if we assume our code will run on just one CPU.
    int64_t create_time_safe()
    {
        using namespace std::chrono;
        int64_t millis = duration_cast<milliseconds>(
                system_clock::now().time_since_epoch()).count();
        uint64_t nanos_since = make_nanos_since(millis);
        if (nanos_since > last_nanos)
            last_nanos = nanos_since;
        else
            nanos_since = ++last_nanos;

        return create_time(nanos_since);
    }

    int64_t create_time_unsafe(int64_t when, int nanos)
    {
        uint64_t nanos_since = make_nanos_since(when) + static_cast<uint64_t>(static_cast<int64_t>(nanos));
        return create_time(nanos_since);
    }

    static int64_t create_time(uint64_t nanos_since)
    {
        uint64_t msb = 0L;
        assert(is_valid_nanos_since(nanos_since));
        msb |= (0x00000000ffffffffL & nanos_since) << 32;
        msb |= (0x0000ffff00000000UL & nanos_since) >> 16;
        msb |= (0x0fff000000000000UL & nanos_since) >> 48;
        msb |= 0x0000000000001000L; // sets the version to 1.
        return msb;
    }
};

// for the curious, here is how I generated START_EPOCH
//        Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT-0"));
//        c.set(Calendar.YEAR, 1582);
//        c.set(Calendar.MONTH, Calendar.OCTOBER);
//        c.set(Calendar.DAY_OF_MONTH, 15);
//        c.set(Calendar.HOUR_OF_DAY, 0);
//        c.set(Calendar.MINUTE, 0);
//        c.set(Calendar.SECOND, 0);
//        c.set(Calendar.MILLISECOND, 0);
//        long START_EPOCH = c.getTimeInMillis();

} // namespace utils
<|endoftext|>


<commit_before>#include <cstdio>
#include <fstream>
#include <unistd.h>

#include <kms++/kms++.h>
#include <kms++util/kms++util.h>

using namespace std;
using namespace kms;

static void read_frame(ifstream& is, DumbFramebuffer* fb, Crtc* crtc, Plane* plane)
{
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		is.read((char*)fb->map(i), fb->size(i));

	unsigned w = min(crtc->width(), fb->width());
	unsigned h = min(crtc->height(), fb->height());

	int r = crtc->set_plane(plane, *fb,
				0, 0, w, h,
				0, 0, fb->width(), fb->height());

	ASSERT(r == 0);
}

static const char* usage_str =
		"Usage: kmsview [-t <ms>] <file> <width> <height> <fourcc>\n\n"
		"Options:\n"
		"  -t, --time        Milliseconds to sleep between frames\n"
		;

static void usage()
{
	puts(usage_str);
}

int main(int argc, char** argv)
{
	uint32_t time = 0;
	string dev_path = "/dev/dri/card0";

	OptionSet optionset = {
		Option("|device=", [&dev_path](string s)
		{
			dev_path = s;
		}),
		Option("t|time=", [&time](const string& str)
		{
			time = stoul(str);
		}),
		Option("h|help", []()
		{
			usage();
			exit(-1);
		}),
	};

	optionset.parse(argc, argv);

	vector<string> params = optionset.params();

	if (params.size() != 4) {
		usage();
		exit(-1);
	}

	string filename = params[0];
	uint32_t w = stoi(params[1]);
	uint32_t h = stoi(params[2]);
	string modestr = params[3];

	auto pixfmt = FourCCToPixelFormat(modestr);

	ifstream is(filename, ifstream::binary);

	is.seekg(0, std::ios::end);
	unsigned fsize = is.tellg();
	is.seekg(0);

	Card card(dev_path);
	ResourceManager res(card);

	auto conn = res.reserve_connector();
	auto crtc = res.reserve_crtc(conn);
	auto plane = res.reserve_overlay_plane(crtc, pixfmt);
	FAIL_IF(!plane, "available plane not found");

	auto fb = new DumbFramebuffer(card, w, h, pixfmt);

	unsigned frame_size = 0;
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		frame_size += fb->size(i);

	unsigned num_frames = fsize / frame_size;
	printf("file size %u, frame size %u, frames %u\n", fsize, frame_size, num_frames);

	for (unsigned i = 0; i < num_frames; ++i) {
		printf("frame %d", i); fflush(stdout);
		read_frame(is, fb, crtc, plane);
		if (!time) {
			getchar();
		} else {
			usleep(time * 1000);
			printf("\n");
		}
	}

	is.close();

	if (time) {
		printf("press enter to exit\n");
		getchar();
	}

	delete fb;
}
<commit_msg>kmsview: Add connector command line argument<commit_after>#include <cstdio>
#include <fstream>
#include <unistd.h>

#include <kms++/kms++.h>
#include <kms++util/kms++util.h>

using namespace std;
using namespace kms;

static void read_frame(ifstream& is, DumbFramebuffer* fb, Crtc* crtc, Plane* plane)
{
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		is.read((char*)fb->map(i), fb->size(i));

	unsigned w = min(crtc->width(), fb->width());
	unsigned h = min(crtc->height(), fb->height());

	int r = crtc->set_plane(plane, *fb,
				0, 0, w, h,
				0, 0, fb->width(), fb->height());

	ASSERT(r == 0);
}

static const char* usage_str =
		"Usage: kmsview [options] <file> <width> <height> <fourcc>\n\n"
		"Options:\n"
		"  -c, --connector <name>	Output connector\n"
		"  -t, --time <ms>		Milliseconds to sleep between frames\n"
		;

static void usage()
{
	puts(usage_str);
}

int main(int argc, char** argv)
{
	uint32_t time = 0;
	string dev_path = "/dev/dri/card0";
	string conn_name;

	OptionSet optionset = {
		Option("c|connector=", [&conn_name](string s)
		{
			conn_name = s;
		}),
		Option("|device=", [&dev_path](string s)
		{
			dev_path = s;
		}),
		Option("t|time=", [&time](const string& str)
		{
			time = stoul(str);
		}),
		Option("h|help", []()
		{
			usage();
			exit(-1);
		}),
	};

	optionset.parse(argc, argv);

	vector<string> params = optionset.params();

	if (params.size() != 4) {
		usage();
		exit(-1);
	}

	string filename = params[0];
	uint32_t w = stoi(params[1]);
	uint32_t h = stoi(params[2]);
	string modestr = params[3];

	auto pixfmt = FourCCToPixelFormat(modestr);

	ifstream is(filename, ifstream::binary);

	is.seekg(0, std::ios::end);
	unsigned fsize = is.tellg();
	is.seekg(0);

	Card card(dev_path);
	ResourceManager res(card);

	auto conn = res.reserve_connector(conn_name);
	auto crtc = res.reserve_crtc(conn);
	auto plane = res.reserve_overlay_plane(crtc, pixfmt);
	FAIL_IF(!plane, "available plane not found");

	auto fb = new DumbFramebuffer(card, w, h, pixfmt);

	unsigned frame_size = 0;
	for (unsigned i = 0; i < fb->num_planes(); ++i)
		frame_size += fb->size(i);

	unsigned num_frames = fsize / frame_size;
	printf("file size %u, frame size %u, frames %u\n", fsize, frame_size, num_frames);

	for (unsigned i = 0; i < num_frames; ++i) {
		printf("frame %d", i); fflush(stdout);
		read_frame(is, fb, crtc, plane);
		if (!time) {
			getchar();
		} else {
			usleep(time * 1000);
			printf("\n");
		}
	}

	is.close();

	if (time) {
		printf("press enter to exit\n");
		getchar();
	}

	delete fb;
}
<|endoftext|>


<commit_before><commit_msg>Arduino 1.0 compliant<commit_after><|endoftext|>


<commit_before>#include	<cstdlib>
#include	<cmath>
#include	<fstream>
#include	<sstream>
#include	<iostream>
#include	<iomanip>
#include	<string>
#include	<vector>
#include	<algorithm>
#include	<exception>
#include	<sys/time.h>
#include	"modules/htmTree.h"
#include	"modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
	//// Initializations ---------------------------------------------
	srand48(1234); // Make sure we have reproducability
	check_args(argc);
	Time t, time; // t for global, time for local
	init_time(t);
	Feat F;
    MTL M;

	// Read parameters file //
	F.readInputFile(argv[1]);
	printFile(argv[1]);
	// Read Secretfile
    // Secret contains the identity of each target: QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF
    Gals Secret;
    printf("before read secretfile \n");
    init_time_at(time,"# read Secret file",t);

    Secret=read_Secretfile(F.Secretfile,F);
    printf("# Read %d galaxies from %s \n",Secret.size(),F.Secretfile.c_str());
	print_time(time,"# ... took :");
    std::vector<int> count(10);
    count=count_galaxies(Secret);
    printf(" Number of galaxies by type, QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF\n");
    for(int i=0;i<8;i++){printf (" type %d number  %d  \n",i, count[i]);}
    //read the three input files
    init_time_at(time,"# read target, SS, SF files",t);
    MTL Targ=read_MTLfile(F.Targfile,F,0,0);
    MTL SStars=read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF=read_MTLfile(F.SkyFfile,F,0,1);
    print_time(time,"# ... took :");
    //combine the three input files
    M=Targ;
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" M size %d \n",M.size());
    F.Ngal=M.size();

    //establish priority classes
    init_time_at(time,"# establish priority clasess",t);
    assign_priority_class(M);
        std::vector <int> count_class(M.priority_list.size(),0);
    for(int i;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
        count_class[M[i].priority_class]+=1;
        }
    }
    for(int i;i<M.priority_list.size();++i){
        printf("  class  %d  number  %d\n",i,count_class[i]);
    }
	print_time(time,"# ... took :");

    // fiber positioners
    PP pp;
	pp.read_fiber_positions(F);
	F.Nfiber = pp.fp.size()/2;
	F.Npetal = max(pp.spectrom)+1;
    F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
	pp.get_neighbors(F);
    pp.compute_fibsofsp(F);

    //P is original list of plates
	Plates P = read_plate_centers(F);
    F.Nplate=P.size();
    printf(" full number of plates %d\n",F.Nplate);
    printf("# Read %d plates from %s and %d fibers from %s\n",F.Nplate,F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

	// Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
	F.cb = create_cb(); // cb=central body
	F.fh = create_fh(); // fh=fiber holder

	//// Collect available galaxies <-> tilefibers --------------------
	// HTM Tree of galaxies
	const double MinTreeSize = 0.01;
	init_time_at(time,"# Start building HTM tree",t);
	htmTree<struct target> T(M,MinTreeSize);
	print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

	// For plates/fibers, collect available galaxies; done in parallel
    collect_galaxies_for_all(M,T,P,pp,F);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);
	// For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
	collect_available_tilefibers(M,P,F);

	//results_on_inputs("doc/figs/",G,P,F,true);

	//// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);

	print_time(t,"# Start assignment at : ");

	// Make a plan ----------------------------------------------------
    // Plans whole survey without sky fibers, standard stars
    // assumes maximum number of observations needed for QSOs, LRGs

    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list
    //and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){

        bool not_done=true;
        for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                inv_count++;

                //and otherwise the position of plate j in list of used plates
            }
        }
    }
    F.NUsedplate=A.suborder.size();
    printf(" Plates actually used %d \n",F.NUsedplate);/*
    for (int j=0;j<F.Nplate;++j){
        printf(" j %d A.inv_order[j]  %d\n",j,A.inv_order[j]);
    }
    for (int jused=0;jused<F.NUsedplate;++jused){
        printf("jused %d  A.suborder[jused] %d\n",jused,A.suborder[jused]);
    }
    */
    if(F.diagnose)diagnostic(M,Secret,F,A);

    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs

	// Smooth out distribution of free fibers, and increase the number of assignments

	for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
	for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
		redistribute_tf(M,P,pp,F,A,0);
	}
	print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);
    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){

        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }
    if(F.diagnose)diagnostic(M,Secret,F,A);
    init_time_at(time,"# Begin real time assignment",t);

	//Execute plan, updating targets at intervals
    for(int i=0;i<F.pass_intervals.size();i++)printf(" i=%d interval %d \n",i,F.pass_intervals[i]);
    std::vector <int> update_intervals=F.pass_intervals;
    update_intervals.push_back(F.NUsedplate);//to end intervals at last plate
    for(int i=0;i<update_intervals.size()-1;++i){//go plate by used plate
        int starter=update_intervals[i];
        for (int jused=starter; jused<update_intervals[i+1]; jused++) {
            if (0<=jused-F.Analysis) update_plan_from_one_obs(jused,Secret,M,P,pp,F,A); else printf("\n no update\n");
            // Update corrects all future occurrences of wrong QSOs etc and tries to observe something else
        }
        redistribute_tf(M,P,pp,F,A,starter);
        improve(M,P,pp,F,A,starter);
        redistribute_tf(M,P,pp,F,A,starter);
        if(F.diagnose)diagnostic(M,Secret,F,A);
    }
    // check on SS and SF

    List SS_hist=initList(11,0);
    List SF_hist=initList(41,0);
    for(int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        for (int p=0;p<F.Npetal;++p){
            int count_SS=0;
            int count_SF=0;
            for (int k=0;k<F.Nfbp;++k){
                int kk=pp.fibers_of_sp[p][k];
                int g=A.TF[j][kk];
                if(g!=-1 && M[g].SS)count_SS++;
                if(g!=-1 && M[g].SF)count_SF++;

            }
            SS_hist[count_SS]++;
            SF_hist[count_SF]++;
        }
    }
    printf(" SS distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SS_hist[i]);
    printf("\n %8d \n",SS_hist[10]);

    printf(" SF distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SF_hist[i]);
    for(int i=10;i<20;i++)printf("%8d",SF_hist[i]);
    for(int i=20;i<30;i++)printf("%8d",SF_hist[i]);
    for(int i=30;i<40;i++)printf("%8d",SF_hist[i]);
    printf("\n %8d \n",SS_hist[40]);

	// Results -------------------------------------------------------
    if (F.PrintAscii) for (int jused=0; jused<F.NUsedplate; jused++){
        write_FAtile_ascii(A.suborder[jused],F.outDir,M,P,pp,F,A);
    }

    if (F.PrintFits) for (int jused=0; jused<F.NUsedplate; jused++){
        fa_write(A.suborder[jused],F.outDir,M,P,pp,F,A); // Write output
    }

	display_results("doc/figs/",Secret,M,P,pp,F,A,true);
	if (F.Verif) A.verif(P,M,pp,F); // Verification that the assignment is sane

	print_time(t,"# Finished !... in");

	return(0);

}
<commit_msg>fix printf at end<commit_after>#include	<cstdlib>
#include	<cmath>
#include	<fstream>
#include	<sstream>
#include	<iostream>
#include	<iomanip>
#include	<string>
#include	<vector>
#include	<algorithm>
#include	<exception>
#include	<sys/time.h>
#include	"modules/htmTree.h"
#include	"modules/kdTree.h"
#include        "misc.h"
#include        "feat.h"
#include        "structs.h"
#include        "collision.h"
#include        "global.h"
//reduce redistributes, updates  07/02/15 rnc
int main(int argc, char **argv) {
	//// Initializations ---------------------------------------------
	srand48(1234); // Make sure we have reproducability
	check_args(argc);
	Time t, time; // t for global, time for local
	init_time(t);
	Feat F;
    MTL M;

	// Read parameters file //
	F.readInputFile(argv[1]);
	printFile(argv[1]);
	// Read Secretfile
    // Secret contains the identity of each target: QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF
    Gals Secret;
    printf("before read secretfile \n");
    init_time_at(time,"# read Secret file",t);

    Secret=read_Secretfile(F.Secretfile,F);
    printf("# Read %d galaxies from %s \n",Secret.size(),F.Secretfile.c_str());
	print_time(time,"# ... took :");
    std::vector<int> count(10);
    count=count_galaxies(Secret);
    printf(" Number of galaxies by type, QSO-Ly-a, QSO-tracers, LRG, ELG, fake QSO, fake LRG, SS, SF\n");
    for(int i=0;i<8;i++){printf (" type %d number  %d  \n",i, count[i]);}
    //read the three input files
    init_time_at(time,"# read target, SS, SF files",t);
    MTL Targ=read_MTLfile(F.Targfile,F,0,0);
    MTL SStars=read_MTLfile(F.SStarsfile,F,1,0);
    MTL SkyF=read_MTLfile(F.SkyFfile,F,0,1);
    print_time(time,"# ... took :");
    //combine the three input files
    M=Targ;
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SStars.begin(),SStars.end());
    printf(" M size %d \n",M.size());
    M.insert(M.end(),SkyF.begin(),SkyF.end());
    printf(" M size %d \n",M.size());
    F.Ngal=M.size();

    //establish priority classes
    init_time_at(time,"# establish priority clasess",t);
    assign_priority_class(M);
        std::vector <int> count_class(M.priority_list.size(),0);
    for(int i;i<M.size();++i){
        if(!M[i].SS&&!M[i].SF){
        count_class[M[i].priority_class]+=1;
        }
    }
    for(int i;i<M.priority_list.size();++i){
        printf("  class  %d  number  %d\n",i,count_class[i]);
    }
	print_time(time,"# ... took :");

    // fiber positioners
    PP pp;
	pp.read_fiber_positions(F);
	F.Nfiber = pp.fp.size()/2;
	F.Npetal = max(pp.spectrom)+1;
    F.Nfbp = (int) (F.Nfiber/F.Npetal);// fibers per petal = 500
	pp.get_neighbors(F);
    pp.compute_fibsofsp(F);

    //P is original list of plates
	Plates P = read_plate_centers(F);
    F.Nplate=P.size();
    printf(" full number of plates %d\n",F.Nplate);
    printf("# Read %d plates from %s and %d fibers from %s\n",F.Nplate,F.tileFile.c_str(),F.Nfiber,F.fibFile.c_str());

	// Computes geometries of cb and fh: pieces of positioner - used to determine possible collisions
	F.cb = create_cb(); // cb=central body
	F.fh = create_fh(); // fh=fiber holder

	//// Collect available galaxies <-> tilefibers --------------------
	// HTM Tree of galaxies
	const double MinTreeSize = 0.01;
	init_time_at(time,"# Start building HTM tree",t);
	htmTree<struct target> T(M,MinTreeSize);
	print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect galaxies at ",t);

	// For plates/fibers, collect available galaxies; done in parallel
    collect_galaxies_for_all(M,T,P,pp,F);
    print_time(time,"# ... took :");//T.stats();
    init_time_at(time,"# collect available tile-fibers at",t);
	// For each galaxy, computes available tilefibers  G[i].av_tfs = [(j1,k1),(j2,k2),..]
	collect_available_tilefibers(M,P,F);

	//results_on_inputs("doc/figs/",G,P,F,true);

	//// Assignment |||||||||||||||||||||||||||||||||||||||||||||||||||
    printf(" Nplate %d  Ngal %d   Nfiber %d \n", F.Nplate, F.Ngal, F.Nfiber);
    Assignment A(M,F);

	print_time(t,"# Start assignment at : ");

	// Make a plan ----------------------------------------------------
    // Plans whole survey without sky fibers, standard stars
    // assumes maximum number of observations needed for QSOs, LRGs

    simple_assign(M,P,pp,F,A);

    //check to see if there are tiles with no galaxies
    //need to keep mapping of old tile list to new tile list
    //and inverse map
    A.inv_order=initList(F.Nplate,-1);
    int inv_count=0;
    for (int j=0;j<F.Nplate ;++j){

        bool not_done=true;
        for(int k=0;k<F.Nfiber && not_done;++k){
            if(A.TF[j][k]!=-1){
                A.suborder.push_back(j);//suborder[jused] is jused-th used plate
                not_done=false;
                A.inv_order[j]=inv_count;//inv_order[j] is -1 unless used
                inv_count++;

                //and otherwise the position of plate j in list of used plates
            }
        }
    }
    F.NUsedplate=A.suborder.size();
    printf(" Plates actually used %d \n",F.NUsedplate);/*
    for (int j=0;j<F.Nplate;++j){
        printf(" j %d A.inv_order[j]  %d\n",j,A.inv_order[j]);
    }
    for (int jused=0;jused<F.NUsedplate;++jused){
        printf("jused %d  A.suborder[jused] %d\n",jused,A.suborder[jused]);
    }
    */
    if(F.diagnose)diagnostic(M,Secret,F,A);

    print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false); // Hist of unused fibs

	// Smooth out distribution of free fibers, and increase the number of assignments

	for (int i=0; i<1; i++) redistribute_tf(M,P,pp,F,A,0);// more iterations will improve performance slightly
	for (int i=0; i<1; i++) {
        improve(M,P,pp,F,A,0);
		redistribute_tf(M,P,pp,F,A,0);
	}
	print_hist("Unused fibers",5,histogram(A.unused_fbp(pp,F),5),false);
    //try assigning SF and SS before real time assignment
    for (int jused=0;jused<F.NUsedplate;++jused){

        int j=A.suborder[jused];
        assign_sf_ss(j,M,P,pp,F,A); // Assign SS and SF for each tile
        assign_unused(j,M,P,pp,F,A);
    }
    if(F.diagnose)diagnostic(M,Secret,F,A);
    init_time_at(time,"# Begin real time assignment",t);

	//Execute plan, updating targets at intervals
    for(int i=0;i<F.pass_intervals.size();i++)printf(" i=%d interval %d \n",i,F.pass_intervals[i]);
    std::vector <int> update_intervals=F.pass_intervals;
    update_intervals.push_back(F.NUsedplate);//to end intervals at last plate
    for(int i=0;i<update_intervals.size()-1;++i){//go plate by used plate
        int starter=update_intervals[i];
        for (int jused=starter; jused<update_intervals[i+1]; jused++) {
            if (0<=jused-F.Analysis) update_plan_from_one_obs(jused,Secret,M,P,pp,F,A); else printf("\n no update\n");
            // Update corrects all future occurrences of wrong QSOs etc and tries to observe something else
        }
        redistribute_tf(M,P,pp,F,A,starter);
        improve(M,P,pp,F,A,starter);
        redistribute_tf(M,P,pp,F,A,starter);
        if(F.diagnose)diagnostic(M,Secret,F,A);
    }
    // check on SS and SF

    List SS_hist=initList(11,0);
    List SF_hist=initList(41,0);
    for(int jused=0;jused<F.NUsedplate;++jused){
        int j=A.suborder[jused];
        for (int p=0;p<F.Npetal;++p){
            int count_SS=0;
            int count_SF=0;
            for (int k=0;k<F.Nfbp;++k){
                int kk=pp.fibers_of_sp[p][k];
                int g=A.TF[j][kk];
                if(g!=-1 && M[g].SS)count_SS++;
                if(g!=-1 && M[g].SF)count_SF++;

            }
            SS_hist[count_SS]++;
            SF_hist[count_SF]++;
        }
    }
    printf(" SS distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SS_hist[i]);
    printf("\n %8d \n",SS_hist[10]);

    printf(" SF distribution \n");
    for(int i=0;i<10;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=10;i<20;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=20;i<30;i++)printf("%8d",SF_hist[i]);
    printf("\n");
    for(int i=30;i<40;i++)printf("%8d",SF_hist[i]);
    printf("\n %8d \n",SS_hist[40]);

	// Results -------------------------------------------------------
    if (F.PrintAscii) for (int jused=0; jused<F.NUsedplate; jused++){
        write_FAtile_ascii(A.suborder[jused],F.outDir,M,P,pp,F,A);
    }

    if (F.PrintFits) for (int jused=0; jused<F.NUsedplate; jused++){
        fa_write(A.suborder[jused],F.outDir,M,P,pp,F,A); // Write output
    }

	display_results("doc/figs/",Secret,M,P,pp,F,A,true);
	if (F.Verif) A.verif(P,M,pp,F); // Verification that the assignment is sane

	print_time(t,"# Finished !... in");

	return(0);

}
<|endoftext|>


<commit_before>#include "ffi.h"

///////////////

void FFI::InitializeStaticFunctions(Handle<Object> target)
{
    Local<Object>       o = Object::New();

    // abs and atoi here for testing purposes
    o->Set(String::New("abs"),      Pointer::WrapPointer((unsigned char *)abs));
    o->Set(String::New("atoi"),     Pointer::WrapPointer((unsigned char *)atoi));
    o->Set(String::New("dlopen"),   Pointer::WrapPointer((unsigned char *)dlopen));
    o->Set(String::New("dlclose"),  Pointer::WrapPointer((unsigned char *)dlclose));
    o->Set(String::New("dlsym"),    Pointer::WrapPointer((unsigned char *)dlsym));
    o->Set(String::New("dlerror"),  Pointer::WrapPointer((unsigned char *)dlerror));

    target->Set(String::NewSymbol("StaticFunctions"), o);
}

///////////////

void FFI::InitializeBindings(Handle<Object> target)
{
    Local<Object> o = Object::New();

    target->Set(String::New("free"),             FunctionTemplate::New(Free)->GetFunction());
    target->Set(String::New("prepCif"),          FunctionTemplate::New(FFIPrepCif)->GetFunction());
    target->Set(String::New("strtoul"),          FunctionTemplate::New(Strtoul)->GetFunction());
    target->Set(String::New("POINTER_SIZE"),     Integer::New(sizeof(unsigned char *)));
    target->Set(String::New("SIZE_SIZE"),        Integer::New(sizeof(size_t))); // DEPRECATED
    target->Set(String::New("FFI_TYPE_SIZE"),    Integer::New(sizeof(ffi_type)));
#if __OBJC__ || __OBJC2__
    target->Set(String::New("HAS_OBJC"),         v8::True(), static_cast<v8::PropertyAttribute>(v8::ReadOnly|v8::DontDelete));
#endif

    Local<Object> smap = Object::New();
    smap->Set(String::New("byte"),      Integer::New(sizeof(unsigned char)));
    smap->Set(String::New("int8"),      Integer::New(sizeof(int8_t)));
    smap->Set(String::New("uint8"),     Integer::New(sizeof(uint8_t)));
    smap->Set(String::New("int16"),     Integer::New(sizeof(int16_t)));
    smap->Set(String::New("uint16"),    Integer::New(sizeof(uint16_t)));
    smap->Set(String::New("int32"),     Integer::New(sizeof(int32_t)));
    smap->Set(String::New("uint32"),    Integer::New(sizeof(uint32_t)));
    smap->Set(String::New("int64"),     Integer::New(sizeof(int64_t)));
    smap->Set(String::New("uint64"),    Integer::New(sizeof(uint64_t)));
    smap->Set(String::New("char"),      Integer::New(sizeof(char)));
    smap->Set(String::New("uchar"),     Integer::New(sizeof(unsigned char)));
    smap->Set(String::New("short"),     Integer::New(sizeof(short)));
    smap->Set(String::New("ushort"),    Integer::New(sizeof(unsigned short)));
    smap->Set(String::New("int"),       Integer::New(sizeof(int)));
    smap->Set(String::New("uint"),      Integer::New(sizeof(unsigned int)));
    smap->Set(String::New("long"),      Integer::New(sizeof(long)));
    smap->Set(String::New("ulong"),     Integer::New(sizeof(unsigned long)));
    smap->Set(String::New("longlong"),  Integer::New(sizeof(long long)));
    smap->Set(String::New("ulonglong"), Integer::New(sizeof(unsigned long long)));
    smap->Set(String::New("float"),     Integer::New(sizeof(float)));
    smap->Set(String::New("double"),    Integer::New(sizeof(double)));
    smap->Set(String::New("pointer"),   Integer::New(sizeof(unsigned char *)));
    smap->Set(String::New("string"),    Integer::New(sizeof(char *)));
    smap->Set(String::New("size_t"),    Integer::New(sizeof(size_t)));
    // Size of a Persistent handle to a JS object
    smap->Set(String::New("Object"),    Integer::New(sizeof(Persistent<Value>)));

    Local<Object> ftmap = Object::New();
    ftmap->Set(String::New("void"),     Pointer::WrapPointer((unsigned char *)&ffi_type_void));
    ftmap->Set(String::New("byte"),     Pointer::WrapPointer((unsigned char *)&ffi_type_uint8));
    ftmap->Set(String::New("int8"),     Pointer::WrapPointer((unsigned char *)&ffi_type_sint8));
    ftmap->Set(String::New("uint8"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uint8));
    ftmap->Set(String::New("uint16"),   Pointer::WrapPointer((unsigned char *)&ffi_type_uint16));
    ftmap->Set(String::New("int16"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sint16));
    ftmap->Set(String::New("uint32"),   Pointer::WrapPointer((unsigned char *)&ffi_type_uint32));
    ftmap->Set(String::New("int32"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sint32));
    ftmap->Set(String::New("uint64"),   Pointer::WrapPointer((unsigned char *)&ffi_type_uint64));
    ftmap->Set(String::New("int64"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sint64));
    ftmap->Set(String::New("uchar"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uchar));
    ftmap->Set(String::New("char"),     Pointer::WrapPointer((unsigned char *)&ffi_type_schar));
    ftmap->Set(String::New("ushort"),   Pointer::WrapPointer((unsigned char *)&ffi_type_ushort));
    ftmap->Set(String::New("short"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sshort));
    ftmap->Set(String::New("uint"),     Pointer::WrapPointer((unsigned char *)&ffi_type_uint));
    ftmap->Set(String::New("int"),      Pointer::WrapPointer((unsigned char *)&ffi_type_sint));
    ftmap->Set(String::New("float"),    Pointer::WrapPointer((unsigned char *)&ffi_type_float));
    ftmap->Set(String::New("double"),   Pointer::WrapPointer((unsigned char *)&ffi_type_double));
    ftmap->Set(String::New("pointer"),  Pointer::WrapPointer((unsigned char *)&ffi_type_pointer));
    ftmap->Set(String::New("string"),   Pointer::WrapPointer((unsigned char *)&ffi_type_pointer));
    ftmap->Set(String::New("size_t"),   Pointer::WrapPointer((unsigned char *)&ffi_type_pointer));

    // libffi is weird when it comes to long data types (defaults to 64-bit), so we emulate here, since
    // some platforms have 32-bit longs and some platforms have 64-bit longs.
    if (sizeof(long) == 4) {
        ftmap->Set(String::New("ulong"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uint32));
        ftmap->Set(String::New("long"),     Pointer::WrapPointer((unsigned char *)&ffi_type_sint32));
    } else if (sizeof(long) == 8) {
        ftmap->Set(String::New("ulong"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uint64));
        ftmap->Set(String::New("long"),     Pointer::WrapPointer((unsigned char *)&ffi_type_sint64));
    }

    // Let libffi handle "long long"
    ftmap->Set(String::New("ulonglong"),Pointer::WrapPointer((unsigned char *)&ffi_type_ulong));
    ftmap->Set(String::New("longlong"), Pointer::WrapPointer((unsigned char *)&ffi_type_slong));

    target->Set(String::New("FFI_TYPES"), ftmap);
    target->Set(String::New("TYPE_SIZE_MAP"), smap);
}

Handle<Value> FFI::Free(const Arguments &args)
{
    HandleScope scope;
    Pointer *p = ObjectWrap::Unwrap<Pointer>(args[0]->ToObject());
    free(p->GetPointer());
    return Undefined();
}

Handle<Value> FFI::Strtoul(const Arguments &args)
{
    HandleScope scope;
    Pointer *middle = ObjectWrap::Unwrap<Pointer>(args[1]->ToObject());
    char buf[128];
    args[0]->ToString()->WriteUtf8(buf);

    unsigned long val = strtoul(buf, (char **)middle->GetPointer(), args[2]->Int32Value());

    return scope.Close(Integer::NewFromUnsigned(val));
}

Handle<Value> FFI::FFIPrepCif(const Arguments& args)
{
    HandleScope scope;

    if (args.Length() == 3) {
        unsigned int nargs  = args[0]->Uint32Value();
        Pointer *rtype      = ObjectWrap::Unwrap<Pointer>(args[1]->ToObject());
        Pointer *atypes     = ObjectWrap::Unwrap<Pointer>(args[2]->ToObject());
        ffi_status status;

        Pointer *cif = new Pointer(NULL);
        cif->Alloc(sizeof(ffi_cif));

        if ((status = ffi_prep_cif(
            (ffi_cif *)cif->GetPointer(),
            FFI_DEFAULT_ABI,
            nargs,
            (ffi_type *)rtype->GetPointer(),
            (ffi_type **)atypes->GetPointer()))) {

            delete cif;
            return THROW_ERROR_EXCEPTION("ffi_prep_cif() returned error.");
        }

        return scope.Close(Pointer::WrapInstance(cif));
    }
    else {
        return THROW_ERROR_EXCEPTION("Not Enough Arguments");
    }
}

///////////////

extern "C" {
  static void init(Handle<Object> target) {
    HandleScope scope;

    Pointer::Initialize(target);
    FFI::InitializeBindings(target);
    FFI::InitializeStaticFunctions(target);
    CallbackInfo::Initialize(target);
    ForeignCaller::Initialize(target);
  }
  NODE_MODULE(ffi_bindings, init);
}
<commit_msg>Remove SIZE_SIZE.<commit_after>#include "ffi.h"

///////////////

void FFI::InitializeStaticFunctions(Handle<Object> target)
{
    Local<Object>       o = Object::New();

    // abs and atoi here for testing purposes
    o->Set(String::New("abs"),      Pointer::WrapPointer((unsigned char *)abs));
    o->Set(String::New("atoi"),     Pointer::WrapPointer((unsigned char *)atoi));
    o->Set(String::New("dlopen"),   Pointer::WrapPointer((unsigned char *)dlopen));
    o->Set(String::New("dlclose"),  Pointer::WrapPointer((unsigned char *)dlclose));
    o->Set(String::New("dlsym"),    Pointer::WrapPointer((unsigned char *)dlsym));
    o->Set(String::New("dlerror"),  Pointer::WrapPointer((unsigned char *)dlerror));

    target->Set(String::NewSymbol("StaticFunctions"), o);
}

///////////////

void FFI::InitializeBindings(Handle<Object> target)
{
    Local<Object> o = Object::New();

    target->Set(String::New("free"),             FunctionTemplate::New(Free)->GetFunction());
    target->Set(String::New("prepCif"),          FunctionTemplate::New(FFIPrepCif)->GetFunction());
    target->Set(String::New("strtoul"),          FunctionTemplate::New(Strtoul)->GetFunction());
    target->Set(String::New("POINTER_SIZE"),     Integer::New(sizeof(unsigned char *)));
    target->Set(String::New("FFI_TYPE_SIZE"),    Integer::New(sizeof(ffi_type)));
#if __OBJC__ || __OBJC2__
    target->Set(String::New("HAS_OBJC"),         v8::True(), static_cast<v8::PropertyAttribute>(v8::ReadOnly|v8::DontDelete));
#endif

    Local<Object> smap = Object::New();
    smap->Set(String::New("byte"),      Integer::New(sizeof(unsigned char)));
    smap->Set(String::New("int8"),      Integer::New(sizeof(int8_t)));
    smap->Set(String::New("uint8"),     Integer::New(sizeof(uint8_t)));
    smap->Set(String::New("int16"),     Integer::New(sizeof(int16_t)));
    smap->Set(String::New("uint16"),    Integer::New(sizeof(uint16_t)));
    smap->Set(String::New("int32"),     Integer::New(sizeof(int32_t)));
    smap->Set(String::New("uint32"),    Integer::New(sizeof(uint32_t)));
    smap->Set(String::New("int64"),     Integer::New(sizeof(int64_t)));
    smap->Set(String::New("uint64"),    Integer::New(sizeof(uint64_t)));
    smap->Set(String::New("char"),      Integer::New(sizeof(char)));
    smap->Set(String::New("uchar"),     Integer::New(sizeof(unsigned char)));
    smap->Set(String::New("short"),     Integer::New(sizeof(short)));
    smap->Set(String::New("ushort"),    Integer::New(sizeof(unsigned short)));
    smap->Set(String::New("int"),       Integer::New(sizeof(int)));
    smap->Set(String::New("uint"),      Integer::New(sizeof(unsigned int)));
    smap->Set(String::New("long"),      Integer::New(sizeof(long)));
    smap->Set(String::New("ulong"),     Integer::New(sizeof(unsigned long)));
    smap->Set(String::New("longlong"),  Integer::New(sizeof(long long)));
    smap->Set(String::New("ulonglong"), Integer::New(sizeof(unsigned long long)));
    smap->Set(String::New("float"),     Integer::New(sizeof(float)));
    smap->Set(String::New("double"),    Integer::New(sizeof(double)));
    smap->Set(String::New("pointer"),   Integer::New(sizeof(unsigned char *)));
    smap->Set(String::New("string"),    Integer::New(sizeof(char *)));
    smap->Set(String::New("size_t"),    Integer::New(sizeof(size_t)));
    // Size of a Persistent handle to a JS object
    smap->Set(String::New("Object"),    Integer::New(sizeof(Persistent<Value>)));

    Local<Object> ftmap = Object::New();
    ftmap->Set(String::New("void"),     Pointer::WrapPointer((unsigned char *)&ffi_type_void));
    ftmap->Set(String::New("byte"),     Pointer::WrapPointer((unsigned char *)&ffi_type_uint8));
    ftmap->Set(String::New("int8"),     Pointer::WrapPointer((unsigned char *)&ffi_type_sint8));
    ftmap->Set(String::New("uint8"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uint8));
    ftmap->Set(String::New("uint16"),   Pointer::WrapPointer((unsigned char *)&ffi_type_uint16));
    ftmap->Set(String::New("int16"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sint16));
    ftmap->Set(String::New("uint32"),   Pointer::WrapPointer((unsigned char *)&ffi_type_uint32));
    ftmap->Set(String::New("int32"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sint32));
    ftmap->Set(String::New("uint64"),   Pointer::WrapPointer((unsigned char *)&ffi_type_uint64));
    ftmap->Set(String::New("int64"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sint64));
    ftmap->Set(String::New("uchar"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uchar));
    ftmap->Set(String::New("char"),     Pointer::WrapPointer((unsigned char *)&ffi_type_schar));
    ftmap->Set(String::New("ushort"),   Pointer::WrapPointer((unsigned char *)&ffi_type_ushort));
    ftmap->Set(String::New("short"),    Pointer::WrapPointer((unsigned char *)&ffi_type_sshort));
    ftmap->Set(String::New("uint"),     Pointer::WrapPointer((unsigned char *)&ffi_type_uint));
    ftmap->Set(String::New("int"),      Pointer::WrapPointer((unsigned char *)&ffi_type_sint));
    ftmap->Set(String::New("float"),    Pointer::WrapPointer((unsigned char *)&ffi_type_float));
    ftmap->Set(String::New("double"),   Pointer::WrapPointer((unsigned char *)&ffi_type_double));
    ftmap->Set(String::New("pointer"),  Pointer::WrapPointer((unsigned char *)&ffi_type_pointer));
    ftmap->Set(String::New("string"),   Pointer::WrapPointer((unsigned char *)&ffi_type_pointer));
    ftmap->Set(String::New("size_t"),   Pointer::WrapPointer((unsigned char *)&ffi_type_pointer));

    // libffi is weird when it comes to long data types (defaults to 64-bit), so we emulate here, since
    // some platforms have 32-bit longs and some platforms have 64-bit longs.
    if (sizeof(long) == 4) {
        ftmap->Set(String::New("ulong"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uint32));
        ftmap->Set(String::New("long"),     Pointer::WrapPointer((unsigned char *)&ffi_type_sint32));
    } else if (sizeof(long) == 8) {
        ftmap->Set(String::New("ulong"),    Pointer::WrapPointer((unsigned char *)&ffi_type_uint64));
        ftmap->Set(String::New("long"),     Pointer::WrapPointer((unsigned char *)&ffi_type_sint64));
    }

    // Let libffi handle "long long"
    ftmap->Set(String::New("ulonglong"),Pointer::WrapPointer((unsigned char *)&ffi_type_ulong));
    ftmap->Set(String::New("longlong"), Pointer::WrapPointer((unsigned char *)&ffi_type_slong));

    target->Set(String::New("FFI_TYPES"), ftmap);
    target->Set(String::New("TYPE_SIZE_MAP"), smap);
}

Handle<Value> FFI::Free(const Arguments &args)
{
    HandleScope scope;
    Pointer *p = ObjectWrap::Unwrap<Pointer>(args[0]->ToObject());
    free(p->GetPointer());
    return Undefined();
}

Handle<Value> FFI::Strtoul(const Arguments &args)
{
    HandleScope scope;
    Pointer *middle = ObjectWrap::Unwrap<Pointer>(args[1]->ToObject());
    char buf[128];
    args[0]->ToString()->WriteUtf8(buf);

    unsigned long val = strtoul(buf, (char **)middle->GetPointer(), args[2]->Int32Value());

    return scope.Close(Integer::NewFromUnsigned(val));
}

Handle<Value> FFI::FFIPrepCif(const Arguments& args)
{
    HandleScope scope;

    if (args.Length() == 3) {
        unsigned int nargs  = args[0]->Uint32Value();
        Pointer *rtype      = ObjectWrap::Unwrap<Pointer>(args[1]->ToObject());
        Pointer *atypes     = ObjectWrap::Unwrap<Pointer>(args[2]->ToObject());
        ffi_status status;

        Pointer *cif = new Pointer(NULL);
        cif->Alloc(sizeof(ffi_cif));

        if ((status = ffi_prep_cif(
            (ffi_cif *)cif->GetPointer(),
            FFI_DEFAULT_ABI,
            nargs,
            (ffi_type *)rtype->GetPointer(),
            (ffi_type **)atypes->GetPointer()))) {

            delete cif;
            return THROW_ERROR_EXCEPTION("ffi_prep_cif() returned error.");
        }

        return scope.Close(Pointer::WrapInstance(cif));
    }
    else {
        return THROW_ERROR_EXCEPTION("Not Enough Arguments");
    }
}

///////////////

extern "C" {
  static void init(Handle<Object> target) {
    HandleScope scope;

    Pointer::Initialize(target);
    FFI::InitializeBindings(target);
    FFI::InitializeStaticFunctions(target);
    CallbackInfo::Initialize(target);
    ForeignCaller::Initialize(target);
  }
  NODE_MODULE(ffi_bindings, init);
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief V8 job
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "V8Job.h"

#include "Basics/json.h"
#include "Basics/logging.h"
#include "V8/v8-conv.h"
#include "V8/v8-utils.h"
#include "V8Server/ApplicationV8.h"
#include "VocBase/vocbase.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new V8 job
////////////////////////////////////////////////////////////////////////////////

V8Job::V8Job (TRI_vocbase_t* vocbase,
              ApplicationV8* v8Dealer,
              std::string const& command,
              TRI_json_t const* parameters)
  : Job("V8 Job"),
    _vocbase(vocbase),
    _v8Dealer(v8Dealer),
    _command(command),
    _parameters(nullptr),
    _canceled(0) {

  if (parameters != nullptr) {
    // create our own copy of the parameters
    _parameters = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, parameters);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a V8 job
////////////////////////////////////////////////////////////////////////////////

V8Job::~V8Job () {
  if (_parameters != nullptr) {
    TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _parameters);
    _parameters = nullptr;
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       Job methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Job::JobType V8Job::type () {
  return READ_JOB;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

string const& V8Job::queue () {
  static const string queue = "STANDARD";
  return queue;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Job::status_t V8Job::work () {
  if (_canceled) {
    return status_t(JOB_DONE);
  }

  ApplicationV8::V8Context* context = _v8Dealer->enterContext("STANDARD", _vocbase, true, false);

  // note: the context might be 0 in case of shut-down
  if (context == nullptr) {
    return status_t(JOB_DONE);
  }

  // now execute the function within this context
  {
    auto isolate = context->isolate;
    v8::HandleScope scope(isolate);

    // get built-in Function constructor (see ECMA-262 5th edition 15.3.2)
    auto current = isolate->GetCurrentContext()->Global();
    auto ctor = v8::Local<v8::Function>::Cast(current->Get(TRI_V8_ASCII_STRING("Function")));

    // Invoke Function constructor to create function with the given body and no arguments
    v8::Handle<v8::Value> args[2] = { TRI_V8_ASCII_STRING("params"), TRI_V8_STD_STRING(_command) };
    v8::Local<v8::Object> function = ctor->NewInstance(2, args);

    v8::Handle<v8::Function> action = v8::Local<v8::Function>::Cast(function);

    if (action.IsEmpty()) {
      _v8Dealer->exitContext(context);
      // TODO: adjust exit code??
      return status_t(JOB_DONE);
    }

    v8::Handle<v8::Value> fArgs;
    if (_parameters != nullptr) {
      fArgs = TRI_ObjectJson(isolate, _parameters);
    }
    else {
      fArgs = v8::Undefined(isolate);
    }

    v8::TryCatch tryCatch;
    // call the function
    action->Call(current, 1, &fArgs);

    if (tryCatch.HasCaught()) {
      if (tryCatch.CanContinue()) {
        TRI_LogV8Exception(isolate, &tryCatch);
      }
      else {
        TRI_GET_GLOBALS();

        v8g->_canceled = true;
        LOG_WARNING("caught non-catchable exception (aka termination) in periodic job");
      }
    }
  }

  _v8Dealer->exitContext(context);

  return status_t(JOB_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

bool V8Job::cancel (bool running) {
  if (running) {
    _canceled = 1;
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

void V8Job::cleanup () {
  delete this;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

bool V8Job::beginShutdown () {
  return true;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

void V8Job::handleError (TriagensError const& ex) {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>moved try/catch into a block<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief V8 job
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "V8Job.h"

#include "Basics/json.h"
#include "Basics/logging.h"
#include "V8/v8-conv.h"
#include "V8/v8-utils.h"
#include "V8Server/ApplicationV8.h"
#include "VocBase/vocbase.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new V8 job
////////////////////////////////////////////////////////////////////////////////

V8Job::V8Job (TRI_vocbase_t* vocbase,
              ApplicationV8* v8Dealer,
              std::string const& command,
              TRI_json_t const* parameters)
  : Job("V8 Job"),
    _vocbase(vocbase),
    _v8Dealer(v8Dealer),
    _command(command),
    _parameters(nullptr),
    _canceled(0) {

  if (parameters != nullptr) {
    // create our own copy of the parameters
    _parameters = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, parameters);
  }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a V8 job
////////////////////////////////////////////////////////////////////////////////

V8Job::~V8Job () {
  if (_parameters != nullptr) {
    TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, _parameters);
    _parameters = nullptr;
  }
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       Job methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Job::JobType V8Job::type () {
  return READ_JOB;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

string const& V8Job::queue () {
  static const string queue = "STANDARD";
  return queue;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Job::status_t V8Job::work () {
  if (_canceled) {
    return status_t(JOB_DONE);
  }

  ApplicationV8::V8Context* context = _v8Dealer->enterContext("STANDARD", _vocbase, true, false);

  // note: the context might be 0 in case of shut-down
  if (context == nullptr) {
    return status_t(JOB_DONE);
  }

  // now execute the function within this context
  {
    auto isolate = context->isolate;
    v8::HandleScope scope(isolate);

    // get built-in Function constructor (see ECMA-262 5th edition 15.3.2)
    auto current = isolate->GetCurrentContext()->Global();
    auto ctor = v8::Local<v8::Function>::Cast(current->Get(TRI_V8_ASCII_STRING("Function")));

    // Invoke Function constructor to create function with the given body and no arguments
    v8::Handle<v8::Value> args[2] = { TRI_V8_ASCII_STRING("params"), TRI_V8_STD_STRING(_command) };
    v8::Local<v8::Object> function = ctor->NewInstance(2, args);

    v8::Handle<v8::Function> action = v8::Local<v8::Function>::Cast(function);

    if (action.IsEmpty()) {
      _v8Dealer->exitContext(context);
      // TODO: adjust exit code??
      return status_t(JOB_DONE);
    }

    v8::Handle<v8::Value> fArgs;

    if (_parameters != nullptr) {
      fArgs = TRI_ObjectJson(isolate, _parameters);
    }
    else {
      fArgs = v8::Undefined(isolate);
    }

    // call the function wihtin a try/catch
    {
      v8::TryCatch tryCatch;

      action->Call(current, 1, &fArgs);

      if (tryCatch.HasCaught()) {
        if (tryCatch.CanContinue()) {
          TRI_LogV8Exception(isolate, &tryCatch);
        }
        else {
          TRI_GET_GLOBALS();

          v8g->_canceled = true;
          LOG_WARNING("caught non-catchable exception (aka termination) in periodic job");
        }
      }
    }
  }

  _v8Dealer->exitContext(context);

  return status_t(JOB_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

bool V8Job::cancel (bool running) {
  if (running) {
    _canceled = 1;
  }

  return true;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

void V8Job::cleanup () {
  delete this;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

bool V8Job::beginShutdown () {
  return true;
}

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

void V8Job::handleError (TriagensError const& ex) {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>