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

#include <cstring>
#include <exception>
#include <string>

#include "phosphor/platform/thread.h"
#include "phosphor/tools/export.h"
#include "phosphor/trace_log.h"
#include "utils/memory.h"
#include "utils/string_utils.h"

namespace phosphor {

    /*
     * TraceLogConfig implementation
     */
    TraceLogConfig::TraceLogConfig()
        // Benchmarking suggests that 4x the number of logical
        // cores is the sweetspot for the number to share.
        : sentinel_count(std::thread::hardware_concurrency() * 4) {}

    TraceLogConfig& TraceLogConfig::setSentinelCount(unsigned _sentinel_count) {
        sentinel_count = _sentinel_count;
        return *this;
    }

    unsigned TraceLogConfig::getSentinelCount() const {
        return sentinel_count;
    }

    TraceLogConfig& TraceLogConfig::setStartupTrace(
        const TraceConfig& _startup_trace) {
        startup_trace = utils::make_unique<TraceConfig>(_startup_trace);
        return *this;
    }

    TraceLogConfig& TraceLogConfig::clearStartupTrace() {
        startup_trace.release();
        return *this;
    }

    TraceConfig* TraceLogConfig::getStartupTrace() const {
        return startup_trace.get();
    }

    TraceLogConfig TraceLogConfig::fromEnvironment() {
        TraceLogConfig config;

        const char* sentinel_count_s = std::getenv("PHOSPHOR_SENTINEL_COUNT");
        if (sentinel_count_s && strlen(sentinel_count_s)) {
            int sentinel_count;
            try {
                sentinel_count = std::stoi(sentinel_count_s);
            } catch (std::invalid_argument& e) {
                throw std::invalid_argument(
                    "TraceLogConfig::fromEnviroment: "
                    "PHOSPHOR_SENTINEL_COUNT was not a valid integer");
            } catch (std::out_of_range& e) {
                throw std::invalid_argument(
                    "TraceLogConfig::fromEnviroment: "
                    "PHOSPHOR_SENTINEL_COUNT was too large");
            }

            if (sentinel_count < 0) {
                throw std::invalid_argument(
                    "TraceLogConfig::fromEnviroment: "
                    "PHOSPHOR_SENTINEL_COUNT cannot be negative");
            }

            config.setSentinelCount(static_cast<unsigned>(sentinel_count));
        }

        const char* startup_config = std::getenv("PHOSPHOR_TRACING_START");
        if (startup_config && strlen(startup_config)) {
            config.setStartupTrace(TraceConfig::fromString(startup_config));
        }

        return config;
    }

    /*
     * TraceConfig implementation
     */

    TraceConfig::TraceConfig(BufferMode _buffer_mode, size_t _buffer_size)
        : buffer_mode(_buffer_mode),
          buffer_size(_buffer_size),
          buffer_factory(modeToFactory(_buffer_mode)) {}

    TraceConfig::TraceConfig(trace_buffer_factory _buffer_factory,
                             size_t _buffer_size)
        : buffer_mode(BufferMode::custom),
          buffer_size(_buffer_size),
          buffer_factory(_buffer_factory) {}

    trace_buffer_factory TraceConfig::modeToFactory(BufferMode mode) {
        switch (mode) {
        case BufferMode::fixed:
            return trace_buffer_factory(make_fixed_buffer);
        case BufferMode::ring:
            return trace_buffer_factory(make_ring_buffer);
        case BufferMode::custom:
            throw std::invalid_argument(
                "phosphor::TraceConfig::modeToFactory: "
                "Cannot get factory for Custom Mode");
        }
        throw std::invalid_argument(
            "phosphor::TraceConfig::modeToFactory:Invalid buffer mode");
    }

    BufferMode TraceConfig::getBufferMode() const {
        return buffer_mode;
    }

    trace_buffer_factory TraceConfig::getBufferFactory() const {
        return buffer_factory;
    }

    size_t TraceConfig::getBufferSize() const {
        return buffer_size;
    }

    TraceConfig& TraceConfig::setStoppedCallback(
        TracingStoppedCallback _tracing_stopped_callback) {
        tracing_stopped_callback = _tracing_stopped_callback;
        return *this;
    }

    TracingStoppedCallback TraceConfig::getStoppedCallback() const {
        return tracing_stopped_callback;
    }

    TraceConfig& TraceConfig::setStopTracingOnDestruct(bool _stop_tracing) {
        stop_tracing = _stop_tracing;
        return *this;
    }

    bool TraceConfig::getStopTracingOnDestruct() const {
        return stop_tracing;
    }

    TraceConfig TraceConfig::fromString(const std::string& config) {
        auto arguments(phosphor::utils::split_string(config, ','));

        BufferMode mode = BufferMode::fixed;
        int buffer_size = 1024 * 1024 * 8;
        std::string filename = "";

        for (const std::string& argument : arguments) {
            auto kv(phosphor::utils::split_string(argument, ':'));
            std::string key(kv[0]);
            std::string value(kv[1]);

            if (key == "buffer-mode") {
                if (value == "fixed") {
                    mode = BufferMode::fixed;
                } else if (value == "ring") {
                    mode = BufferMode::ring;
                } else {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "Invalid buffer mode given");
                }
            } else if (key == "buffer-size") {
                try {
                    buffer_size = std::stoi(value);
                } catch (std::invalid_argument& e) {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "buffer size was not a valid integer");
                } catch (std::out_of_range& e) {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "buffer size was too large");
                }

                if (buffer_size < 0) {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "buffer size cannot be negative");
                }
            } else if (key == "save-on-stop") {
                filename = value;
            }
        }

        TraceConfig config_obj(mode, static_cast<size_t>(buffer_size));
        if (filename != "") {
            config_obj.setStoppedCallback(tools::FileStopCallback(filename));
            config_obj.setStopTracingOnDestruct(true);
        }
        return config_obj;
    }

    /*
     * TraceLog implementation
     */

    TraceLog::TraceLog(const TraceLogConfig& _config) : enabled(false) {
        configure(_config);
    }

    TraceLog::TraceLog() : TraceLog(TraceLogConfig::fromEnvironment()) {}

    TraceLog::~TraceLog() {
        stop(true);
        for (auto& chunk : shared_chunks) {
            delete chunk.sentinel;
        }
    }

    void TraceLog::configure(const TraceLogConfig& _config) {
        std::lock_guard<TraceLog> lh(*this);

        shared_chunks.reserve(_config.getSentinelCount());
        registered_sentinels.reserve(_config.getSentinelCount());
        for (size_t i = shared_chunks.size(); i < _config.getSentinelCount(); ++i) {
            shared_chunks.emplace_back();
            shared_chunks[i].sentinel = new Sentinel;
            registered_sentinels.insert(shared_chunks[i].sentinel);
        }

        if (auto* startup_trace = _config.getStartupTrace()) {
            start(lh, *startup_trace);
        }
    }

    TraceLog& TraceLog::getInstance() {
        // TODO: Not thread-safe on Windows
        static TraceLog log_instance;
        return log_instance;
    }

    void TraceLog::stop(bool shutdown) {
        std::lock_guard<TraceLog> lh(*this);
        stop(lh, shutdown);
    }

    void TraceLog::stop(std::lock_guard<TraceLog>& lh, bool shutdown) {
        if (enabled.exchange(false)) {
            evictThreads(lh);
            auto cb = trace_config.getStoppedCallback();
            if (cb && (!shutdown || trace_config.getStopTracingOnDestruct())) {
                cb(*this, lh);
            }
        }
    }

    void TraceLog::start(const TraceConfig& _trace_config) {
        std::lock_guard<TraceLog> lh(*this);
        start(lh, _trace_config);
    }

    void TraceLog::start(std::lock_guard<TraceLog>&,
                         const TraceConfig& _trace_config) {
        trace_config = _trace_config;

        size_t buffer_size = trace_config.getBufferSize() / sizeof(TraceChunk);
        if (buffer_size == 0) {
            throw std::invalid_argument(
                "Cannot specify a buffer size less than a single chunk (" +
                std::to_string(sizeof(TraceChunk)) + " bytes)");
        }

        buffer = trace_config.getBufferFactory()(generation++, buffer_size);
        enabled.store(true);
    }

    std::unique_ptr<TraceBuffer> TraceLog::getBuffer() {
        std::lock_guard<TraceLog> lh(*this);
        return getBuffer(lh);
    }

    std::unique_ptr<TraceBuffer> TraceLog::getBuffer(
        std::lock_guard<TraceLog>&) {
        if (enabled) {
            throw std::logic_error(
                "phosphor::TraceLog::getBuffer: Cannot get the current "
                "TraceBuffer while logging is enabled");
        }
        return std::move(buffer);
    }

    bool TraceLog::isEnabled() {
        return enabled;
    }

    void TraceLog::registerThread() {
        std::lock_guard<TraceLog> lh(*this);

        thread_chunk.sentinel = new Sentinel;
        registered_sentinels.insert(thread_chunk.sentinel);
    }

    void TraceLog::deregisterThread() {
        std::lock_guard<TraceLog> lh(*this);

        if (!thread_chunk.sentinel) {
            throw std::logic_error(
                "phosphor::TraceLog::deregisterThread: This thread has "
                "not been previously registered");
        }

        if (thread_chunk.chunk) {
            std::lock_guard<std::mutex> lh(instance.mutex);
            if (instance.buffer) {
                instance.buffer->returnChunk(*thread_chunk.chunk);
            }
        }
        registered_sentinels.erase(thread_chunk.sentinel);
        delete thread_chunk.sentinel;
    }

    void TraceLog::replaceChunk(ChunkTenant& ct) {
        ct.sentinel->release();
        std::lock_guard<TraceLog> lh(*this);
        if (!ct.sentinel->acquire()) {
            resetChunk(ct);
            return;
        }
        if (!enabled) {
            ct.chunk = nullptr;
            ct.sentinel->release();
            return;
        }

        if (ct.chunk) {
            buffer->returnChunk(*ct.chunk);
            ct.chunk = nullptr;
        }
        if (!(buffer && (ct.chunk = buffer->getChunk()))) {
            ct.sentinel->release();
            stop(lh);
        }
    }

    void TraceLog::resetChunk(ChunkTenant& ct) {
        if (ct.sentinel->reopen()) {
            ct.chunk = nullptr;
            ct.sentinel->release();
        }
    }

    void TraceLog::evictThreads(std::lock_guard<TraceLog>& lh) {
        for(auto& sentinel : registered_sentinels) {
            sentinel->close();
        }
    }

    THREAD_LOCAL TraceLog::ChunkTenant TraceLog::thread_chunk;
}
<commit_msg>Stop getting global lock when replacing chunks<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include <cstring>
#include <exception>
#include <string>

#include "phosphor/platform/thread.h"
#include "phosphor/tools/export.h"
#include "phosphor/trace_log.h"
#include "utils/memory.h"
#include "utils/string_utils.h"

namespace phosphor {

    /*
     * TraceLogConfig implementation
     */
    TraceLogConfig::TraceLogConfig()
        // Benchmarking suggests that 4x the number of logical
        // cores is the sweetspot for the number to share.
        : sentinel_count(std::thread::hardware_concurrency() * 4) {}

    TraceLogConfig& TraceLogConfig::setSentinelCount(unsigned _sentinel_count) {
        sentinel_count = _sentinel_count;
        return *this;
    }

    unsigned TraceLogConfig::getSentinelCount() const {
        return sentinel_count;
    }

    TraceLogConfig& TraceLogConfig::setStartupTrace(
        const TraceConfig& _startup_trace) {
        startup_trace = utils::make_unique<TraceConfig>(_startup_trace);
        return *this;
    }

    TraceLogConfig& TraceLogConfig::clearStartupTrace() {
        startup_trace.release();
        return *this;
    }

    TraceConfig* TraceLogConfig::getStartupTrace() const {
        return startup_trace.get();
    }

    TraceLogConfig TraceLogConfig::fromEnvironment() {
        TraceLogConfig config;

        const char* sentinel_count_s = std::getenv("PHOSPHOR_SENTINEL_COUNT");
        if (sentinel_count_s && strlen(sentinel_count_s)) {
            int sentinel_count;
            try {
                sentinel_count = std::stoi(sentinel_count_s);
            } catch (std::invalid_argument& e) {
                throw std::invalid_argument(
                    "TraceLogConfig::fromEnviroment: "
                    "PHOSPHOR_SENTINEL_COUNT was not a valid integer");
            } catch (std::out_of_range& e) {
                throw std::invalid_argument(
                    "TraceLogConfig::fromEnviroment: "
                    "PHOSPHOR_SENTINEL_COUNT was too large");
            }

            if (sentinel_count < 0) {
                throw std::invalid_argument(
                    "TraceLogConfig::fromEnviroment: "
                    "PHOSPHOR_SENTINEL_COUNT cannot be negative");
            }

            config.setSentinelCount(static_cast<unsigned>(sentinel_count));
        }

        const char* startup_config = std::getenv("PHOSPHOR_TRACING_START");
        if (startup_config && strlen(startup_config)) {
            config.setStartupTrace(TraceConfig::fromString(startup_config));
        }

        return config;
    }

    /*
     * TraceConfig implementation
     */

    TraceConfig::TraceConfig(BufferMode _buffer_mode, size_t _buffer_size)
        : buffer_mode(_buffer_mode),
          buffer_size(_buffer_size),
          buffer_factory(modeToFactory(_buffer_mode)) {}

    TraceConfig::TraceConfig(trace_buffer_factory _buffer_factory,
                             size_t _buffer_size)
        : buffer_mode(BufferMode::custom),
          buffer_size(_buffer_size),
          buffer_factory(_buffer_factory) {}

    trace_buffer_factory TraceConfig::modeToFactory(BufferMode mode) {
        switch (mode) {
        case BufferMode::fixed:
            return trace_buffer_factory(make_fixed_buffer);
        case BufferMode::ring:
            return trace_buffer_factory(make_ring_buffer);
        case BufferMode::custom:
            throw std::invalid_argument(
                "phosphor::TraceConfig::modeToFactory: "
                "Cannot get factory for Custom Mode");
        }
        throw std::invalid_argument(
            "phosphor::TraceConfig::modeToFactory:Invalid buffer mode");
    }

    BufferMode TraceConfig::getBufferMode() const {
        return buffer_mode;
    }

    trace_buffer_factory TraceConfig::getBufferFactory() const {
        return buffer_factory;
    }

    size_t TraceConfig::getBufferSize() const {
        return buffer_size;
    }

    TraceConfig& TraceConfig::setStoppedCallback(
        TracingStoppedCallback _tracing_stopped_callback) {
        tracing_stopped_callback = _tracing_stopped_callback;
        return *this;
    }

    TracingStoppedCallback TraceConfig::getStoppedCallback() const {
        return tracing_stopped_callback;
    }

    TraceConfig& TraceConfig::setStopTracingOnDestruct(bool _stop_tracing) {
        stop_tracing = _stop_tracing;
        return *this;
    }

    bool TraceConfig::getStopTracingOnDestruct() const {
        return stop_tracing;
    }

    TraceConfig TraceConfig::fromString(const std::string& config) {
        auto arguments(phosphor::utils::split_string(config, ','));

        BufferMode mode = BufferMode::fixed;
        int buffer_size = 1024 * 1024 * 8;
        std::string filename = "";

        for (const std::string& argument : arguments) {
            auto kv(phosphor::utils::split_string(argument, ':'));
            std::string key(kv[0]);
            std::string value(kv[1]);

            if (key == "buffer-mode") {
                if (value == "fixed") {
                    mode = BufferMode::fixed;
                } else if (value == "ring") {
                    mode = BufferMode::ring;
                } else {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "Invalid buffer mode given");
                }
            } else if (key == "buffer-size") {
                try {
                    buffer_size = std::stoi(value);
                } catch (std::invalid_argument& e) {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "buffer size was not a valid integer");
                } catch (std::out_of_range& e) {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "buffer size was too large");
                }

                if (buffer_size < 0) {
                    throw std::invalid_argument(
                        "TraceConfig::fromString: "
                        "buffer size cannot be negative");
                }
            } else if (key == "save-on-stop") {
                filename = value;
            }
        }

        TraceConfig config_obj(mode, static_cast<size_t>(buffer_size));
        if (filename != "") {
            config_obj.setStoppedCallback(tools::FileStopCallback(filename));
            config_obj.setStopTracingOnDestruct(true);
        }
        return config_obj;
    }

    /*
     * TraceLog implementation
     */

    TraceLog::TraceLog(const TraceLogConfig& _config) : enabled(false) {
        configure(_config);
    }

    TraceLog::TraceLog() : TraceLog(TraceLogConfig::fromEnvironment()) {}

    TraceLog::~TraceLog() {
        stop(true);
        for (auto& chunk : shared_chunks) {
            delete chunk.sentinel;
        }
    }

    void TraceLog::configure(const TraceLogConfig& _config) {
        std::lock_guard<TraceLog> lh(*this);

        shared_chunks.reserve(_config.getSentinelCount());
        registered_sentinels.reserve(_config.getSentinelCount());
        for (size_t i = shared_chunks.size(); i < _config.getSentinelCount(); ++i) {
            shared_chunks.emplace_back();
            shared_chunks[i].sentinel = new Sentinel;
            registered_sentinels.insert(shared_chunks[i].sentinel);
        }

        if (auto* startup_trace = _config.getStartupTrace()) {
            start(lh, *startup_trace);
        }
    }

    TraceLog& TraceLog::getInstance() {
        // TODO: Not thread-safe on Windows
        static TraceLog log_instance;
        return log_instance;
    }

    void TraceLog::stop(bool shutdown) {
        std::lock_guard<TraceLog> lh(*this);
        stop(lh, shutdown);
    }

    void TraceLog::stop(std::lock_guard<TraceLog>& lh, bool shutdown) {
        if (enabled.exchange(false)) {
            evictThreads(lh);
            auto cb = trace_config.getStoppedCallback();
            if (cb && (!shutdown || trace_config.getStopTracingOnDestruct())) {
                cb(*this, lh);
            }
        }
    }

    void TraceLog::start(const TraceConfig& _trace_config) {
        std::lock_guard<TraceLog> lh(*this);
        start(lh, _trace_config);
    }

    void TraceLog::start(std::lock_guard<TraceLog>&,
                         const TraceConfig& _trace_config) {
        trace_config = _trace_config;

        size_t buffer_size = trace_config.getBufferSize() / sizeof(TraceChunk);
        if (buffer_size == 0) {
            throw std::invalid_argument(
                "Cannot specify a buffer size less than a single chunk (" +
                std::to_string(sizeof(TraceChunk)) + " bytes)");
        }

        buffer = trace_config.getBufferFactory()(generation++, buffer_size);
        enabled.store(true);
    }

    std::unique_ptr<TraceBuffer> TraceLog::getBuffer() {
        std::lock_guard<TraceLog> lh(*this);
        return getBuffer(lh);
    }

    std::unique_ptr<TraceBuffer> TraceLog::getBuffer(
        std::lock_guard<TraceLog>&) {
        if (enabled) {
            throw std::logic_error(
                "phosphor::TraceLog::getBuffer: Cannot get the current "
                "TraceBuffer while logging is enabled");
        }
        return std::move(buffer);
    }

    bool TraceLog::isEnabled() {
        return enabled;
    }

    void TraceLog::registerThread() {
        std::lock_guard<TraceLog> lh(*this);

        thread_chunk.sentinel = new Sentinel;
        registered_sentinels.insert(thread_chunk.sentinel);
    }

    void TraceLog::deregisterThread() {
        std::lock_guard<TraceLog> lh(*this);

        if (!thread_chunk.sentinel) {
            throw std::logic_error(
                "phosphor::TraceLog::deregisterThread: This thread has "
                "not been previously registered");
        }

        if (thread_chunk.chunk) {
            if (buffer) {
                buffer->returnChunk(*thread_chunk.chunk);
            }
            thread_chunk.chunk = nullptr;
        }
        registered_sentinels.erase(thread_chunk.sentinel);
        delete thread_chunk.sentinel;
    }

    void TraceLog::replaceChunk(ChunkTenant& ct) {
        if (ct.chunk) {
            buffer->returnChunk(*ct.chunk);
            ct.chunk = nullptr;
        }
        if (!(buffer && (ct.chunk = buffer->getChunk()))) {
            ct.sentinel->release();
            stop();
        }
    }

    void TraceLog::resetChunk(ChunkTenant& ct) {
        if (ct.sentinel->reopen()) {
            ct.chunk = nullptr;
            ct.sentinel->release();
        }
    }

    void TraceLog::evictThreads(std::lock_guard<TraceLog>& lh) {
        for(auto& sentinel : registered_sentinels) {
            sentinel->close();
        }
    }

    THREAD_LOCAL TraceLog::ChunkTenant TraceLog::thread_chunk;
}
<|endoftext|>


<commit_before>#ifndef ACCUMULATE__H__
#define ACCUMULATE__H__

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>
#include <functional>
#include <type_traits>

namespace iter {

    //Forward declarations of Accumulator and accumulate
    template <typename Container, typename AccumulateFunc>
    class Accumulator;

    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&&, AccumulateFunc);

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T>, AccumulateFunc);

    template <typename Container, typename AccumulateFunc>
    class Accumulator {
        private:
            Container container;
            AccumulateFunc accumulate_func;

            friend Accumulator accumulate<Container, AccumulateFunc>(
                    Container&&, AccumulateFunc);

            template <typename T, typename AF>
            friend Accumulator<std::initializer_list<T>, AF> accumulate(
                    std::initializer_list<T>, AF);

            // Value constructor for use only in the accumulate function
            Accumulator(Container container, AccumulateFunc accumulate_func)
                : container(std::forward<Container>(container)),
                accumulate_func(accumulate_func)
            { }
            Accumulator() = delete;
            Accumulator& operator=(const Accumulator&) = delete;

        public:
            Accumulator(const Accumulator&) = default;

            class Iterator {
                // AccumVal must be default constructible
                using AccumVal =
                    typename std::remove_reference<
                        typename std::result_of<AccumulateFunc(
                                iterator_deref<Container>,
                                iterator_deref<Container>)>::type>::type;
                static_assert(
                        std::is_default_constructible<AccumVal>::value,
                        "Cannot accumulate a non-default constructible type");

                private:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    AccumulateFunc accumulate_func;
                    AccumVal acc_val;
                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            AccumulateFunc accumulate_func)
                        : sub_iter{iter},
                        sub_end{end},
                        accumulate_func(accumulate_func),
                        // only get first value if not an end iterator
                        acc_val(!(iter != end) ? AccumVal{} : *iter)
                    { }

                    AccumVal operator*() const {
                        return this->acc_val;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        if (this->sub_iter != this->sub_end) {
                            this->acc_val = accumulate_func(
                                    this->acc_val, *this->sub_iter);
                        }
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

    };

    // Helper function to instantiate an Accumulator
    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&& container,
            AccumulateFunc accumulate_func)
    {
        return {std::forward<Container>(container), accumulate_func};
    }

    template <typename Container>
    auto accumulate(Container&& container) ->
        decltype(accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{}))
    {
        return accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{});
    }

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T> il,
            AccumulateFunc accumulate_func)
    {
        return {std::move(il), accumulate_func};
    }

    template <typename T>
    auto accumulate(std::initializer_list<T> il) ->
        decltype(accumulate(std::move(il), std::plus<T>{}))
    {
        return accumulate(std::move(il), std::plus<T>{});
    }

}

#endif //ifndef ACCUMULATE__H__
<commit_msg>removes __ from include guards<commit_after>#ifndef ITER_ACCUMULATE_H_
#define ITER_ACCUMULATE_H_

#include "iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>
#include <functional>
#include <type_traits>

namespace iter {

    //Forward declarations of Accumulator and accumulate
    template <typename Container, typename AccumulateFunc>
    class Accumulator;

    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&&, AccumulateFunc);

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T>, AccumulateFunc);

    template <typename Container, typename AccumulateFunc>
    class Accumulator {
        private:
            Container container;
            AccumulateFunc accumulate_func;

            friend Accumulator accumulate<Container, AccumulateFunc>(
                    Container&&, AccumulateFunc);

            template <typename T, typename AF>
            friend Accumulator<std::initializer_list<T>, AF> accumulate(
                    std::initializer_list<T>, AF);

            // Value constructor for use only in the accumulate function
            Accumulator(Container container, AccumulateFunc accumulate_func)
                : container(std::forward<Container>(container)),
                accumulate_func(accumulate_func)
            { }
            Accumulator() = delete;
            Accumulator& operator=(const Accumulator&) = delete;

        public:
            Accumulator(const Accumulator&) = default;

            class Iterator {
                // AccumVal must be default constructible
                using AccumVal =
                    typename std::remove_reference<
                        typename std::result_of<AccumulateFunc(
                                iterator_deref<Container>,
                                iterator_deref<Container>)>::type>::type;
                static_assert(
                        std::is_default_constructible<AccumVal>::value,
                        "Cannot accumulate a non-default constructible type");

                private:
                    iterator_type<Container> sub_iter;
                    const iterator_type<Container> sub_end;
                    AccumulateFunc accumulate_func;
                    AccumVal acc_val;
                public:
                    Iterator (iterator_type<Container> iter,
                            iterator_type<Container> end,
                            AccumulateFunc accumulate_func)
                        : sub_iter{iter},
                        sub_end{end},
                        accumulate_func(accumulate_func),
                        // only get first value if not an end iterator
                        acc_val(!(iter != end) ? AccumVal{} : *iter)
                    { }

                    AccumVal operator*() const {
                        return this->acc_val;
                    }

                    Iterator& operator++() {
                        ++this->sub_iter;
                        if (this->sub_iter != this->sub_end) {
                            this->acc_val = accumulate_func(
                                    this->acc_val, *this->sub_iter);
                        }
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->sub_iter != other.sub_iter;
                    }
            };

            Iterator begin() {
                return {std::begin(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

            Iterator end() {
                return {std::end(this->container),
                        std::end(this->container),
                        this->accumulate_func};
            }

    };

    // Helper function to instantiate an Accumulator
    template <typename Container, typename AccumulateFunc>
    Accumulator<Container, AccumulateFunc> accumulate(
            Container&& container,
            AccumulateFunc accumulate_func)
    {
        return {std::forward<Container>(container), accumulate_func};
    }

    template <typename Container>
    auto accumulate(Container&& container) ->
        decltype(accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{}))
    {
        return accumulate(std::forward<Container>(container),
                    std::plus<typename std::remove_reference<
                        iterator_deref<Container>>::type>{});
    }

    template <typename T, typename AccumulateFunc>
    Accumulator<std::initializer_list<T>, AccumulateFunc> accumulate(
            std::initializer_list<T> il,
            AccumulateFunc accumulate_func)
    {
        return {std::move(il), accumulate_func};
    }

    template <typename T>
    auto accumulate(std::initializer_list<T> il) ->
        decltype(accumulate(std::move(il), std::plus<T>{}))
    {
        return accumulate(std::move(il), std::plus<T>{});
    }

}

#endif //ifndef ITER_ACCUMULATE_H_
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/SVD>

/* this test covers the following files:
   Geometry/OrthoMethods.h
*/

template<typename Scalar> void orthomethods_3()
{
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar,3,3> Matrix3;
  typedef Matrix<Scalar,3,1> Vector3;

  typedef Matrix<Scalar,4,1> Vector4;

  Vector3 v0 = Vector3::Random(),
          v1 = Vector3::Random(),
          v2 = Vector3::Random();

  // cross product
  VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v1), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v1.dot(v1.cross(v2)), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v2), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v2.dot(v1.cross(v2)), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(Vector3::Random()).dot(v1), Scalar(1));
  Matrix3 mat3;
  mat3 << v0.normalized(),
         (v0.cross(v1)).normalized(),
         (v0.cross(v1).cross(v0)).normalized();
  VERIFY(mat3.isUnitary());

  // colwise/rowwise cross product
  mat3.setRandom();
  Vector3 vec3 = Vector3::Random();
  Matrix3 mcross;
  int i = internal::random<int>(0,2);
  mcross = mat3.colwise().cross(vec3);
  VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));

  VERIFY_IS_MUCH_SMALLER_THAN((mat3.transpose() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN((mat3.transpose() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(), Scalar(1));

  VERIFY_IS_MUCH_SMALLER_THAN((vec3.transpose() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN((vec3.transpose() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));

  mcross = mat3.rowwise().cross(vec3);
  VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));

  // cross3
  Vector4 v40 = Vector4::Random(),
          v41 = Vector4::Random(),
          v42 = Vector4::Random();
  v40.w() = v41.w() = v42.w() = 0;
  v42.template head<3>() = v40.template head<3>().cross(v41.template head<3>());
  VERIFY_IS_APPROX(v40.cross3(v41), v42);
  VERIFY_IS_MUCH_SMALLER_THAN(v40.cross3(Vector4::Random()).dot(v40), Scalar(1));

  // check mixed product
  typedef Matrix<RealScalar, 3, 1> RealVector3;
  RealVector3 rv1 = RealVector3::Random();
  VERIFY_IS_APPROX(v1.cross(rv1.template cast<Scalar>()), v1.cross(rv1));
  VERIFY_IS_APPROX(rv1.template cast<Scalar>().cross(v1), rv1.cross(v1));
}

template<typename Scalar, int Size> void orthomethods(int size=Size)
{
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar,Size,1> VectorType;
  typedef Matrix<Scalar,3,Size> Matrix3N;
  typedef Matrix<Scalar,Size,3> MatrixN3;
  typedef Matrix<Scalar,3,1> Vector3;

  VectorType v0 = VectorType::Random(size);

  // unitOrthogonal
  VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
  VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));

  if (size>=3)
  {
    v0.template head<2>().setZero();
    v0.tail(size-2).setRandom();

    VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
    VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
  }

  // colwise/rowwise cross product
  Vector3 vec3 = Vector3::Random();
  int i = internal::random<int>(0,size-1);

  Matrix3N mat3N(3,size), mcross3N(3,size);
  mat3N.setRandom();
  mcross3N = mat3N.colwise().cross(vec3);
  VERIFY_IS_APPROX(mcross3N.col(i), mat3N.col(i).cross(vec3));

  MatrixN3 matN3(size,3), mcrossN3(size,3);
  matN3.setRandom();
  mcrossN3 = matN3.rowwise().cross(vec3);
  VERIFY_IS_APPROX(mcrossN3.row(i), matN3.row(i).cross(vec3));
}

void test_geo_orthomethods()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( orthomethods_3<float>() );
    CALL_SUBTEST_2( orthomethods_3<double>() );
    CALL_SUBTEST_4( orthomethods_3<std::complex<double> >() );
    CALL_SUBTEST_1( (orthomethods<float,2>()) );
    CALL_SUBTEST_2( (orthomethods<double,2>()) );
    CALL_SUBTEST_1( (orthomethods<float,3>()) );
    CALL_SUBTEST_2( (orthomethods<double,3>()) );
    CALL_SUBTEST_3( (orthomethods<float,7>()) );
    CALL_SUBTEST_4( (orthomethods<std::complex<double>,8>()) );
    CALL_SUBTEST_5( (orthomethods<float,Dynamic>(36)) );
    CALL_SUBTEST_6( (orthomethods<double,Dynamic>(35)) );
  }
}
<commit_msg>Fix geo_orthomethods unit test for complexes<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2009 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"
#include <Eigen/Geometry>
#include <Eigen/LU>
#include <Eigen/SVD>

/* this test covers the following files:
   Geometry/OrthoMethods.h
*/

template<typename Scalar> void orthomethods_3()
{
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar,3,3> Matrix3;
  typedef Matrix<Scalar,3,1> Vector3;

  typedef Matrix<Scalar,4,1> Vector4;

  Vector3 v0 = Vector3::Random(),
          v1 = Vector3::Random(),
          v2 = Vector3::Random();

  // cross product
  VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v1), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v1.dot(v1.cross(v2)), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(v2).dot(v2), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v2.dot(v1.cross(v2)), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN(v1.cross(Vector3::Random()).dot(v1), Scalar(1));
  Matrix3 mat3;
  mat3 << v0.normalized(),
         (v0.cross(v1)).normalized(),
         (v0.cross(v1).cross(v0)).normalized();
  VERIFY(mat3.isUnitary());

  // colwise/rowwise cross product
  mat3.setRandom();
  Vector3 vec3 = Vector3::Random();
  Matrix3 mcross;
  int i = internal::random<int>(0,2);
  mcross = mat3.colwise().cross(vec3);
  VERIFY_IS_APPROX(mcross.col(i), mat3.col(i).cross(vec3));

  VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(vec3)).diagonal().cwiseAbs().sum(), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN((mat3.adjoint() * mat3.colwise().cross(Vector3::Random())).diagonal().cwiseAbs().sum(), Scalar(1));

  VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * mat3.colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));
  VERIFY_IS_MUCH_SMALLER_THAN((vec3.adjoint() * Matrix3::Random().colwise().cross(vec3)).cwiseAbs().sum(), Scalar(1));

  mcross = mat3.rowwise().cross(vec3);
  VERIFY_IS_APPROX(mcross.row(i), mat3.row(i).cross(vec3));

  // cross3
  Vector4 v40 = Vector4::Random(),
          v41 = Vector4::Random(),
          v42 = Vector4::Random();
  v40.w() = v41.w() = v42.w() = 0;
  v42.template head<3>() = v40.template head<3>().cross(v41.template head<3>());
  VERIFY_IS_APPROX(v40.cross3(v41), v42);
  VERIFY_IS_MUCH_SMALLER_THAN(v40.cross3(Vector4::Random()).dot(v40), Scalar(1));

  // check mixed product
  typedef Matrix<RealScalar, 3, 1> RealVector3;
  RealVector3 rv1 = RealVector3::Random();
  VERIFY_IS_APPROX(v1.cross(rv1.template cast<Scalar>()), v1.cross(rv1));
  VERIFY_IS_APPROX(rv1.template cast<Scalar>().cross(v1), rv1.cross(v1));
}

template<typename Scalar, int Size> void orthomethods(int size=Size)
{
  typedef typename NumTraits<Scalar>::Real RealScalar;
  typedef Matrix<Scalar,Size,1> VectorType;
  typedef Matrix<Scalar,3,Size> Matrix3N;
  typedef Matrix<Scalar,Size,3> MatrixN3;
  typedef Matrix<Scalar,3,1> Vector3;

  VectorType v0 = VectorType::Random(size);

  // unitOrthogonal
  VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
  VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));

  if (size>=3)
  {
    v0.template head<2>().setZero();
    v0.tail(size-2).setRandom();

    VERIFY_IS_MUCH_SMALLER_THAN(v0.unitOrthogonal().dot(v0), Scalar(1));
    VERIFY_IS_APPROX(v0.unitOrthogonal().norm(), RealScalar(1));
  }

  // colwise/rowwise cross product
  Vector3 vec3 = Vector3::Random();
  int i = internal::random<int>(0,size-1);

  Matrix3N mat3N(3,size), mcross3N(3,size);
  mat3N.setRandom();
  mcross3N = mat3N.colwise().cross(vec3);
  VERIFY_IS_APPROX(mcross3N.col(i), mat3N.col(i).cross(vec3));

  MatrixN3 matN3(size,3), mcrossN3(size,3);
  matN3.setRandom();
  mcrossN3 = matN3.rowwise().cross(vec3);
  VERIFY_IS_APPROX(mcrossN3.row(i), matN3.row(i).cross(vec3));
}

void test_geo_orthomethods()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( orthomethods_3<float>() );
    CALL_SUBTEST_2( orthomethods_3<double>() );
    CALL_SUBTEST_4( orthomethods_3<std::complex<double> >() );
    CALL_SUBTEST_1( (orthomethods<float,2>()) );
    CALL_SUBTEST_2( (orthomethods<double,2>()) );
    CALL_SUBTEST_1( (orthomethods<float,3>()) );
    CALL_SUBTEST_2( (orthomethods<double,3>()) );
    CALL_SUBTEST_3( (orthomethods<float,7>()) );
    CALL_SUBTEST_4( (orthomethods<std::complex<double>,8>()) );
    CALL_SUBTEST_5( (orthomethods<float,Dynamic>(36)) );
    CALL_SUBTEST_6( (orthomethods<double,Dynamic>(35)) );
  }
}
<|endoftext|>


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

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

#pragma once

#include "sstables/sstables.hh"
#include "memtable-sstable.hh"
#include "dht/i_partitioner.hh"
#include <boost/range/irange.hpp>
#include <boost/range/adaptor/map.hpp>

struct local_shard_only_tag { };
using local_shard_only = bool_class<local_shard_only_tag>;

sstables::shared_sstable make_sstable_containing(std::function<sstables::shared_sstable()> sst_factory, std::vector<mutation> muts);

inline future<> write_memtable_to_sstable_for_test(memtable& mt, sstables::shared_sstable sst) {
    return write_memtable_to_sstable(mt, sst);
}

//
// Make set of keys sorted by token for current or remote shard.
//
static std::vector<sstring> do_make_keys(unsigned n, const schema_ptr& s, size_t min_key_size = 1, local_shard_only lso = local_shard_only::yes) {
    std::vector<std::pair<sstring, dht::decorated_key>> p;
    p.reserve(n);

    auto key_id = 0U;
    auto generated = 0U;
    while (generated < n) {
        auto raw_key = sstring(std::max(min_key_size, sizeof(key_id)), int8_t(0));
        std::copy_n(reinterpret_cast<int8_t*>(&key_id), sizeof(key_id), raw_key.begin());
        auto dk = dht::decorate_key(*s, partition_key::from_single_value(*s, to_bytes(raw_key)));
        key_id++;
        if (lso) {
            if (engine_is_ready() && engine().cpu_id() != dht::global_partitioner().shard_of(dk.token())) {
                continue;
            }
        }
        generated++;
        p.emplace_back(std::move(raw_key), std::move(dk));
    }
    boost::sort(p, [&] (auto& p1, auto& p2) {
        return p1.second.less_compare(*s, p2.second);
    });
    return boost::copy_range<std::vector<sstring>>(p | boost::adaptors::map_keys);
}

inline std::vector<sstring> make_local_keys(unsigned n, const schema_ptr& s, size_t min_key_size = 1) {
    return do_make_keys(n, s, min_key_size, local_shard_only::yes);
}

inline sstring make_local_key(const schema_ptr& s, size_t min_key_size = 1) {
    return do_make_keys(1, s, min_key_size, local_shard_only::yes).front();
}

inline std::vector<sstring> make_keys(unsigned n, const schema_ptr& s, size_t min_key_size = 1) {
    return do_make_keys(n, s, min_key_size, local_shard_only::no);
}
<commit_msg>sstable_utils: stop calling global_partitioner()<commit_after>/*
 * Copyright (C) 2017 ScyllaDB
 */

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

#pragma once

#include "sstables/sstables.hh"
#include "memtable-sstable.hh"
#include "dht/i_partitioner.hh"
#include <boost/range/irange.hpp>
#include <boost/range/adaptor/map.hpp>

struct local_shard_only_tag { };
using local_shard_only = bool_class<local_shard_only_tag>;

sstables::shared_sstable make_sstable_containing(std::function<sstables::shared_sstable()> sst_factory, std::vector<mutation> muts);

inline future<> write_memtable_to_sstable_for_test(memtable& mt, sstables::shared_sstable sst) {
    return write_memtable_to_sstable(mt, sst);
}

//
// Make set of keys sorted by token for current or remote shard.
//
static std::vector<sstring> do_make_keys(unsigned n, const schema_ptr& s, size_t min_key_size = 1, local_shard_only lso = local_shard_only::yes) {
    std::vector<std::pair<sstring, dht::decorated_key>> p;
    p.reserve(n);

    auto key_id = 0U;
    auto generated = 0U;
    while (generated < n) {
        auto raw_key = sstring(std::max(min_key_size, sizeof(key_id)), int8_t(0));
        std::copy_n(reinterpret_cast<int8_t*>(&key_id), sizeof(key_id), raw_key.begin());
        auto dk = dht::decorate_key(*s, partition_key::from_single_value(*s, to_bytes(raw_key)));
        key_id++;
        if (lso) {
            if (engine_is_ready() && engine().cpu_id() != shard_of(*s, dk.token())) {
                continue;
            }
        }
        generated++;
        p.emplace_back(std::move(raw_key), std::move(dk));
    }
    boost::sort(p, [&] (auto& p1, auto& p2) {
        return p1.second.less_compare(*s, p2.second);
    });
    return boost::copy_range<std::vector<sstring>>(p | boost::adaptors::map_keys);
}

inline std::vector<sstring> make_local_keys(unsigned n, const schema_ptr& s, size_t min_key_size = 1) {
    return do_make_keys(n, s, min_key_size, local_shard_only::yes);
}

inline sstring make_local_key(const schema_ptr& s, size_t min_key_size = 1) {
    return do_make_keys(1, s, min_key_size, local_shard_only::yes).front();
}

inline std::vector<sstring> make_keys(unsigned n, const schema_ptr& s, size_t min_key_size = 1) {
    return do_make_keys(n, s, min_key_size, local_shard_only::no);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <algorithm>
#include <stdio.h>

#include <boost/timer/timer.hpp>

#include <imageprocessing/SubStackSelector.h>
#include <util/ProgramOptions.h>
#include "MinimalImpactTEDWriter.h"

util::ProgramOption optionNumAdjacentSections(
		util::_module           = "sopnet.training",
		util::_long_name        = "numAdjacentSections",
		util::_default_value    = 0,
		util::_description_text = "The number of adjacent sections to consider for the computation of the minimal impact TED coefficients. If set to 0 (default), all sections will be considered.");

util::ProgramOption optionLimitToISI(
		util::_module           = "sopnet.training",
		util::_long_name        = "limitToISI",
		util::_description_text = "If set, limits the computation of the TED coefficients to segments in the given inter-section interval.");

static logger::LogChannel minimalImpactTEDlog("minimalImpactTEDlog", "[minimalImapctTED] ");

MinimalImpactTEDWriter::MinimalImpactTEDWriter() :
	_teDistance(boost::make_shared<TolerantEditDistance>()),
	_gsimCreator(boost::make_shared<IdMapCreator>()),
	_rimCreator(boost::make_shared<IdMapCreator>()),
	_rNeuronExtractor(boost::make_shared<NeuronExtractor>()),
	_gsNeuronExtractor(boost::make_shared<NeuronExtractor>()),
	_rReconstructor(boost::make_shared<Reconstructor>()),
	_linearSolver(boost::make_shared<LinearSolver>()),
	_objectiveGenerator(boost::make_shared<ObjectiveGenerator>()),
	_hammingCostFunction(boost::make_shared<HammingCostFunction>())
	{

	registerInput(_goldStandard, "gold standard");
	registerInput(_linearConstraints, "linear constraints");
	registerInput(_segments, "segments");
	registerInput(_reference, "reference");
	registerInput(_problemConfiguration, "problem configuration");

}

void
MinimalImpactTEDWriter::write(std::string filename) {

	updateInputs();

	initPipeline();

	int limitToISI = -1;
	if (optionLimitToISI)
		limitToISI = optionLimitToISI.as<int>() - SliceHashConfiguration::sectionOffset;

	// append ISI number to output filename
	if (limitToISI >= 0)
		filename = filename + "_" + optionLimitToISI.as<std::string>();

	LOG_USER(minimalImpactTEDlog) << "writing ted coefficients to " << filename << std::endl;

	// Remove the old file
	if( remove( filename.c_str() ) != 0 ) {
		LOG_DEBUG(minimalImpactTEDlog) << "Old file to output minimal impact TED approximation sucessfully deleted." << std::endl;
	}
	else {
		LOG_DEBUG(minimalImpactTEDlog) << "Could not delete old file to output minimal impact TED approximation." << std::endl;
	}

	// Open file for writing
	std::ofstream outfile;
	outfile.open(filename.c_str(), std::ios_base::app);

	 // Get a vector with all gold standard segments.
	const std::vector<boost::shared_ptr<Segment> > goldStandard = _goldStandard->getSegments();

	int constant = 0;

	// Loop through variables
	std::set<unsigned int> variables = _problemConfiguration->getVariables();

	LOG_USER(minimalImpactTEDlog) << "computing ted coefficients for " << variables.size() << " variables" << std::endl;

	outfile << "numVar " << variables.size() << std::endl;

	outfile << "# var_num costs # hash value_in_gs fs fm fp fn ( <- when flipped )" << std::endl;

	std::set<unsigned int> goldStandardIds;
	foreach (boost::shared_ptr<Segment> s, goldStandard)
		goldStandardIds.insert(s->getId());

	// create a map from segment ids to segment pointers
	std::map<unsigned int, boost::shared_ptr<Segment> > idToSegment;
	foreach (boost::shared_ptr<Segment> segment, _segments->getSegments())
		idToSegment[segment->getId()] = segment;

	for ( unsigned int varNum = 0 ; varNum < variables.size() ; varNum++ ) {

		unsigned int segmentId = _problemConfiguration->getSegmentId(varNum);

		int interSectionInterval = _problemConfiguration->getInterSectionInterval(varNum);

		if (limitToISI >= 0)
			if (interSectionInterval != limitToISI)
				continue;

		std::string timerMessage = "\n\nMinimalImpactTEDWriter: variable " + boost::lexical_cast<std::string>(varNum) + ", %ws\n\n";
		boost::timer::auto_cpu_timer timer(timerMessage);

		// re-create the pipeline for the current segment and its inter-section
		// interval
		updatePipeline(interSectionInterval, optionNumAdjacentSections.as<int>());

		// Is the segment that corresponds to the variable part of the gold standard?
		bool isContained = (goldStandardIds.count(segmentId) > 0);

		// get the hash value of this segment
		SegmentHash segmentHash = idToSegment[segmentId]->hashValue();

		// pin the value of the current variable to its opposite
		_linearSolver->pinVariable(varNum, (isContained ? 0 : 1));

		pipeline::Value<Errors> errors = _teDistance->getOutput("errors");
		int sumErrors = errors->getNumSplits() + errors->getNumMerges() + errors->getNumFalsePositives() + errors->getNumFalseNegatives();

		outfile << "c" << varNum << " ";
		outfile << (isContained ? -sumErrors : sumErrors) << " ";
		outfile << "# ";
		outfile << segmentHash << " ";
		outfile << (isContained ? 1 : 0) << " ";
		outfile << errors->getNumSplits() << " ";
		outfile << errors->getNumMerges() << " ";
		outfile << errors->getNumFalsePositives() << " ";
		outfile << errors->getNumFalseNegatives() << std::endl;

		if (isContained) {

			// Forced segment to not be part of the reconstruction.
			// This resulted in a number of errors that are going to be stored in the constant.
			// To make net 0 errors when the variable is on, minus the number of errors will be written to the file.

			constant += sumErrors;
		}

		// Remove constraint
		_linearSolver->unpinVariable(varNum);
	}

	// Write constant to file
	outfile << "constant " << constant << std::endl;

	outfile.close();
}

void
MinimalImpactTEDWriter::initPipeline() {

	// Here we assemble the static part of the pipeline, i.e., the parts that
	// don't change between iterations. Currently, these are all parts below the
	// linear solver that creates new reconstructions based on pinned variables;
	// and everything below the gold standard id map creator.

	_hammingCostFunction = boost::make_shared<HammingCostFunction>();
	_objectiveGenerator = boost::make_shared<ObjectiveGenerator>();
	_linearSolver = boost::make_shared<LinearSolver>();

	_gsNeuronExtractor = boost::make_shared<NeuronExtractor>();
	_gsimCreator = boost::make_shared<IdMapCreator>();

	// -- Gold Standard --> Hamming Cost Function
	_hammingCostFunction->setInput("gold standard", _goldStandard);

	// -- Segments --> Objective Generator
	_objectiveGenerator->setInput("segments", _segments);
	// Hamming Cost Function ----> Objective Generator
	_objectiveGenerator->addInput("cost functions", _hammingCostFunction->getOutput());

	// -- Linear Constraints --> Linear Solver
	_linearSolver->setInput("linear constraints",_linearConstraints);
	// -- Parameters --> Linear Solver
	_linearSolver->setInput("parameters", boost::make_shared<LinearSolverParameters>(Binary));
	// Objective Generator ----> Linear Solver
	_linearSolver->setInput("objective", _objectiveGenerator->getOutput());

	// -- gold standard --> NeuronExtractor [gold standard]
	_gsNeuronExtractor->setInput("segments", _goldStandard);
	// NeuronExtractor [gold standard] ----> IdMapCreator [gold standard]
	_gsimCreator->setInput("neurons", _gsNeuronExtractor->getOutput("neurons"));
	// reference image stack for width height and size of output image stacks
	// -- reference --> IdMapCreator
	_gsimCreator->setInput("reference", _reference);
}

void
MinimalImpactTEDWriter::updatePipeline(int interSectionInterval, int numAdjacentSections) {

	boost::timer::auto_cpu_timer timer("\tupdatePipeline()\t\t\t%ws\n");

	// create new pipeline components
	_teDistance = boost::make_shared<TolerantEditDistance>();
	_rimCreator = boost::make_shared<IdMapCreator>();
	_rNeuronExtractor = boost::make_shared<NeuronExtractor>();
	_rReconstructor = boost::make_shared<Reconstructor>();

	// find the range of sections to consider for the computation of the TED
	int minSection = interSectionInterval - numAdjacentSections;
	int maxSection = interSectionInterval + numAdjacentSections - 1;

	// pipeline values for the image stacks used to compute the TED
	pipeline::Value<ImageStack> goldStandard;
	pipeline::Value<ImageStack> reconstruction;

	// get image stacks for TED either as subsets (if numAdjacentSections is
	// set) or as the original stacks
	if (numAdjacentSections > 0) {

		pipeline::Process<SubStackSelector> goldStandardSelector(minSection, maxSection);
		pipeline::Process<SubStackSelector> reconstructionSelector(minSection, maxSection);

		goldStandardSelector->setInput(_gsimCreator->getOutput("id map"));
		reconstructionSelector->setInput(_rimCreator->getOutput("id map"));

		goldStandard   = goldStandardSelector->getOutput();
		reconstruction = reconstructionSelector->getOutput();

	} else {

		goldStandard = _gsimCreator->getOutput("id map");
		reconstruction = _rimCreator->getOutput("id map");
	}

	// Set inputs

	// The name ground truth is slightly misleading here because really we are setting the gold standard as input,
	// but that is what the correct input in the TED is called.
	// IdMapCreator [gold standard] ----> TED
	_teDistance->setInput("ground truth", goldStandard);
	// IdMapCreator [reconstruction] ----> TED
	_teDistance->setInput("reconstruction", reconstruction);
	// Reconstructor ----> NeuronExtractor [reconstruction]
	_rNeuronExtractor->setInput("segments", _rReconstructor->getOutput("reconstruction"));
	// NeuronExtractor [reconstruction] ----> IdMapCreator [reconstruction]
	_rimCreator->setInput("neurons", _rNeuronExtractor->getOutput("neurons"));
	// reference image stack for width height and size of output image stack
	// -- reference --> IdMapCreator
	_rimCreator->setInput("reference",_reference);
	// Linear Solver ----> Reconstructor
	_rReconstructor->setInput("solution", _linearSolver->getOutput("solution"));
	// -- Segments --> Reconstructor
	_rReconstructor->setInput("segments",_segments);
}
<commit_msg>added option to write TED conditions to MinimalImpactTEDWriter<commit_after>#include <iostream>
#include <fstream>
#include <algorithm>
#include <stdio.h>

#include <boost/timer/timer.hpp>

#include <imageprocessing/SubStackSelector.h>
#include <util/ProgramOptions.h>
#include "MinimalImpactTEDWriter.h"

util::ProgramOption optionNumAdjacentSections(
		util::_module           = "sopnet.training",
		util::_long_name        = "numAdjacentSections",
		util::_default_value    = 0,
		util::_description_text = "The number of adjacent sections to consider for the computation of the minimal impact TED coefficients. If set to 0 (default), all sections will be considered.");

util::ProgramOption optionLimitToISI(
		util::_module           = "sopnet.training",
		util::_long_name        = "limitToISI",
		util::_description_text = "If set, limits the computation of the TED coefficients to segments in the given inter-section interval.");

util::ProgramOption optionWriteTedConditions(
		util::_module           = "sopnet.training",
		util::_long_name        = "writeTedConditions",
		util::_description_text = "Instead of computing the TED coefficients, write TED conditions to file minimalImapctTEDconditions.txt: "
		                          "These are the individual solutions that are used to compute the TED for a pinned segment variable.");

static logger::LogChannel minimalImpactTEDlog("minimalImpactTEDlog", "[minimalImapctTED] ");

MinimalImpactTEDWriter::MinimalImpactTEDWriter() :
	_teDistance(boost::make_shared<TolerantEditDistance>()),
	_gsimCreator(boost::make_shared<IdMapCreator>()),
	_rimCreator(boost::make_shared<IdMapCreator>()),
	_rNeuronExtractor(boost::make_shared<NeuronExtractor>()),
	_gsNeuronExtractor(boost::make_shared<NeuronExtractor>()),
	_rReconstructor(boost::make_shared<Reconstructor>()),
	_linearSolver(boost::make_shared<LinearSolver>()),
	_objectiveGenerator(boost::make_shared<ObjectiveGenerator>()),
	_hammingCostFunction(boost::make_shared<HammingCostFunction>())
	{

	registerInput(_goldStandard, "gold standard");
	registerInput(_linearConstraints, "linear constraints");
	registerInput(_segments, "segments");
	registerInput(_reference, "reference");
	registerInput(_problemConfiguration, "problem configuration");

}

void
MinimalImpactTEDWriter::write(std::string filename) {

	updateInputs();

	initPipeline();

	int limitToISI = -1;
	if (optionLimitToISI)
		limitToISI = optionLimitToISI.as<int>() - SliceHashConfiguration::sectionOffset;

	if (optionWriteTedConditions)
		filename = "minimalImapctTEDconditions.txt";

	// append ISI number to output filename
	if (limitToISI >= 0)
		filename = filename + "_" + optionLimitToISI.as<std::string>();

	if (optionWriteTedConditions) {
		LOG_USER(minimalImpactTEDlog) << "writing ted conditions to " << filename << std::endl;
	} else {
		LOG_USER(minimalImpactTEDlog) << "writing ted coefficients to " << filename << std::endl;
	}

	// Remove the old file
	if( remove( filename.c_str() ) != 0 ) {
		LOG_DEBUG(minimalImpactTEDlog) << "Old file to output minimal impact TED approximation sucessfully deleted." << std::endl;
	}
	else {
		LOG_DEBUG(minimalImpactTEDlog) << "Could not delete old file to output minimal impact TED approximation." << std::endl;
	}

	// Open file for writing
	std::ofstream outfile;

	outfile.open(filename.c_str(), std::ios_base::app);

	 // Get a vector with all gold standard segments.
	const std::vector<boost::shared_ptr<Segment> > goldStandard = _goldStandard->getSegments();

	int constant = 0;

	// Loop through variables
	std::set<unsigned int> variables = _problemConfiguration->getVariables();

	LOG_USER(minimalImpactTEDlog) << "computing ted coefficients for " << variables.size() << " variables" << std::endl;

	if (!optionWriteTedConditions) {

		outfile << "numVar " << variables.size() << std::endl;
		outfile << "# var_num costs # hash value_in_gs fs fm fp fn ( <- when flipped )" << std::endl;
	}

	std::set<unsigned int> goldStandardIds;
	foreach (boost::shared_ptr<Segment> s, goldStandard)
		goldStandardIds.insert(s->getId());

	// create a map from segment ids to segment pointers
	std::map<unsigned int, boost::shared_ptr<Segment> > idToSegment;
	foreach (boost::shared_ptr<Segment> segment, _segments->getSegments())
		idToSegment[segment->getId()] = segment;

	for ( unsigned int varNum = 0 ; varNum < variables.size() ; varNum++ ) {

		unsigned int segmentId = _problemConfiguration->getSegmentId(varNum);

		int interSectionInterval = _problemConfiguration->getInterSectionInterval(varNum);

		if (limitToISI >= 0)
			if (interSectionInterval != limitToISI)
				continue;

		std::string timerMessage = "\n\nMinimalImpactTEDWriter: variable " + boost::lexical_cast<std::string>(varNum) + ", %ws\n\n";
		boost::timer::auto_cpu_timer timer(timerMessage);

		// re-create the pipeline for the current segment and its inter-section
		// interval
		if (!optionWriteTedConditions)
			updatePipeline(interSectionInterval, optionNumAdjacentSections.as<int>());

		// Is the segment that corresponds to the variable part of the gold standard?
		bool isContained = (goldStandardIds.count(segmentId) > 0);

		// get the hash value of this segment
		SegmentHash segmentHash = idToSegment[segmentId]->hashValue();

		// pin the value of the current variable to its opposite
		_linearSolver->pinVariable(varNum, (isContained ? 0 : 1));

		if (!optionWriteTedConditions) {

			pipeline::Value<Errors> errors = _teDistance->getOutput("errors");
			int sumErrors = errors->getNumSplits() + errors->getNumMerges() + errors->getNumFalsePositives() + errors->getNumFalseNegatives();

			outfile << "c" << varNum << " ";
			outfile << (isContained ? -sumErrors : sumErrors) << " ";
			outfile << "# ";
			outfile << segmentHash << " ";
			outfile << (isContained ? 1 : 0) << " ";
			outfile << errors->getNumSplits() << " ";
			outfile << errors->getNumMerges() << " ";
			outfile << errors->getNumFalsePositives() << " ";
			outfile << errors->getNumFalseNegatives() << std::endl;

			if (isContained) {

				// Forced segment to not be part of the reconstruction.
				// This resulted in a number of errors that are going to be stored in the constant.
				// To make net 0 errors when the variable is on, minus the number of errors will be written to the file.

				constant += sumErrors;
			}

		} else {

			pipeline::Value<Solution> solution = _linearSolver->getOutput("solution");

			outfile << varNum << " " << segmentHash;
			for (unsigned int i = 0; i < variables.size(); i++)
				outfile << " " << (*solution)[i];
			outfile << std::endl;
		}

		// Remove constraint
		_linearSolver->unpinVariable(varNum);
	}

	if (!optionWriteTedConditions) {

		// Write constant to file
		outfile << "constant " << constant << std::endl;
	}

	outfile.close();
}

void
MinimalImpactTEDWriter::initPipeline() {

	// Here we assemble the static part of the pipeline, i.e., the parts that
	// don't change between iterations. Currently, these are all parts below the
	// linear solver that creates new reconstructions based on pinned variables;
	// and everything below the gold standard id map creator.

	_hammingCostFunction = boost::make_shared<HammingCostFunction>();
	_objectiveGenerator = boost::make_shared<ObjectiveGenerator>();
	_linearSolver = boost::make_shared<LinearSolver>();

	_gsNeuronExtractor = boost::make_shared<NeuronExtractor>();
	_gsimCreator = boost::make_shared<IdMapCreator>();

	// -- Gold Standard --> Hamming Cost Function
	_hammingCostFunction->setInput("gold standard", _goldStandard);

	// -- Segments --> Objective Generator
	_objectiveGenerator->setInput("segments", _segments);
	// Hamming Cost Function ----> Objective Generator
	_objectiveGenerator->addInput("cost functions", _hammingCostFunction->getOutput());

	// -- Linear Constraints --> Linear Solver
	_linearSolver->setInput("linear constraints",_linearConstraints);
	// -- Parameters --> Linear Solver
	_linearSolver->setInput("parameters", boost::make_shared<LinearSolverParameters>(Binary));
	// Objective Generator ----> Linear Solver
	_linearSolver->setInput("objective", _objectiveGenerator->getOutput());

	// -- gold standard --> NeuronExtractor [gold standard]
	_gsNeuronExtractor->setInput("segments", _goldStandard);
	// NeuronExtractor [gold standard] ----> IdMapCreator [gold standard]
	_gsimCreator->setInput("neurons", _gsNeuronExtractor->getOutput("neurons"));
	// reference image stack for width height and size of output image stacks
	// -- reference --> IdMapCreator
	_gsimCreator->setInput("reference", _reference);
}

void
MinimalImpactTEDWriter::updatePipeline(int interSectionInterval, int numAdjacentSections) {

	boost::timer::auto_cpu_timer timer("\tupdatePipeline()\t\t\t%ws\n");

	// create new pipeline components
	_teDistance = boost::make_shared<TolerantEditDistance>();
	_rimCreator = boost::make_shared<IdMapCreator>();
	_rNeuronExtractor = boost::make_shared<NeuronExtractor>();
	_rReconstructor = boost::make_shared<Reconstructor>();

	// find the range of sections to consider for the computation of the TED
	int minSection = interSectionInterval - numAdjacentSections;
	int maxSection = interSectionInterval + numAdjacentSections - 1;

	// pipeline values for the image stacks used to compute the TED
	pipeline::Value<ImageStack> goldStandard;
	pipeline::Value<ImageStack> reconstruction;

	// get image stacks for TED either as subsets (if numAdjacentSections is
	// set) or as the original stacks
	if (numAdjacentSections > 0) {

		pipeline::Process<SubStackSelector> goldStandardSelector(minSection, maxSection);
		pipeline::Process<SubStackSelector> reconstructionSelector(minSection, maxSection);

		goldStandardSelector->setInput(_gsimCreator->getOutput("id map"));
		reconstructionSelector->setInput(_rimCreator->getOutput("id map"));

		goldStandard   = goldStandardSelector->getOutput();
		reconstruction = reconstructionSelector->getOutput();

	} else {

		goldStandard = _gsimCreator->getOutput("id map");
		reconstruction = _rimCreator->getOutput("id map");
	}

	// Set inputs

	// The name ground truth is slightly misleading here because really we are setting the gold standard as input,
	// but that is what the correct input in the TED is called.
	// IdMapCreator [gold standard] ----> TED
	_teDistance->setInput("ground truth", goldStandard);
	// IdMapCreator [reconstruction] ----> TED
	_teDistance->setInput("reconstruction", reconstruction);
	// Reconstructor ----> NeuronExtractor [reconstruction]
	_rNeuronExtractor->setInput("segments", _rReconstructor->getOutput("reconstruction"));
	// NeuronExtractor [reconstruction] ----> IdMapCreator [reconstruction]
	_rimCreator->setInput("neurons", _rNeuronExtractor->getOutput("neurons"));
	// reference image stack for width height and size of output image stack
	// -- reference --> IdMapCreator
	_rimCreator->setInput("reference",_reference);
	// Linear Solver ----> Reconstructor
	_rReconstructor->setInput("solution", _linearSolver->getOutput("solution"));
	// -- Segments --> Reconstructor
	_rReconstructor->setInput("segments",_segments);
}
<|endoftext|>


<commit_before>// ------------------------------------------------------------------
// pion-net: a C++ framework for building lightweight HTTP interfaces
// ------------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#include <boost/bind.hpp>
#include <pion/net/PionNet.hpp>
#include <iostream>
#include <vector>
#ifndef PION_WIN32
	#include <signal.h>
#endif

// these are used only when linking to static web service libraries
// #ifdef PION_STATIC_LINKING
PION_DECLARE_PLUGIN(EchoService)
PION_DECLARE_PLUGIN(FileService)
PION_DECLARE_PLUGIN(HelloService)
PION_DECLARE_PLUGIN(LogService)
PION_DECLARE_PLUGIN(CookieService)

using namespace std;
using namespace pion;
using namespace pion::net;

/// stops Pion when it receives signals
#ifdef PION_WIN32
BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
{
	switch(ctrl_type) {
		case CTRL_C_EVENT:
		case CTRL_BREAK_EVENT:
		case CTRL_CLOSE_EVENT:
		case CTRL_SHUTDOWN_EVENT:
			PionNet::shutdown();
			return TRUE;
		default:
			return FALSE;
	}
}
#else
void handle_signal(int sig)
{
	PionNet::shutdown();
}
#endif

/// displays an error message if the arguments are invalid
void argument_error(void)
{
	std::cerr << "usage:   PionServiceTest [OPTIONS] RESOURCE WEBSERVICE" << std::endl
		      << "         PionServiceTest [OPTIONS] -c SERVICE_CONFIG_FILE" << std::endl
			  << "options: [-ssl PEM_FILE] [-p PORT] [-d SERVICE_PLUGINS_DIR] [-o OPTION=VALUE]" << std::endl;
}

/// main control function
int main (int argc, char *argv[])
{
	static const unsigned int DEFAULT_PORT = 8080;

	// used to keep track of web service name=value options
	typedef std::vector<std::pair<std::string, std::string> >	ServiceOptionsType;
	ServiceOptionsType service_options;

	// parse command line: determine port number, RESOURCE and WEBSERVICE
	unsigned int port = DEFAULT_PORT;
	std::string service_config_file;
	std::string resource_name;
	std::string service_name;
	std::string ssl_pem_file;
	bool ssl_flag = false;

	for (int argnum=1; argnum < argc; ++argnum) {
		if (argv[argnum][0] == '-') {
			if (argv[argnum][1] == 'p' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				++argnum;
				port = strtoul(argv[argnum], 0, 10);
				if (port == 0) port = DEFAULT_PORT;
			} else if (argv[argnum][1] == 'c' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				service_config_file = argv[++argnum];
			} else if (argv[argnum][1] == 'd' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				// add the service plug-ins directory to the search path
				try { PionNet::addPluginDirectory(argv[++argnum]); }
				catch (PionPlugin::DirectoryNotFoundException&) {
					std::cerr << "PionServiceTest: Web service plug-ins directory does not exist: "
						<< argv[argnum] << std::endl;
					return 1;
				}
			} else if (argv[argnum][1] == 'o' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				std::string option_name(argv[++argnum]);
				std::string::size_type pos = option_name.find('=');
				if (pos == std::string::npos) {
					argument_error();
					return 1;
				}
				std::string option_value(option_name, pos + 1);
				option_name.resize(pos);
				service_options.push_back( std::make_pair(option_name, option_value) );
			} else if (argv[argnum][1] == 's' && argv[argnum][2] == 's' &&
					   argv[argnum][3] == 'l' && argv[argnum][4] == '\0' && argnum+1 < argc) {
				ssl_flag = true;
				ssl_pem_file = argv[++argnum];
			} else {
				argument_error();
				return 1;
			}
		} else if (argnum+2 == argc) {
			// second to last argument = RESOURCE
			resource_name = argv[argnum];
		} else if (argnum+1 == argc) {
			// last argument = WEBSERVICE
			service_name = argv[argnum];
		} else {
			argument_error();
			return 1;
		}
	}

	if (service_config_file.empty() && (resource_name.empty() || service_name.empty())) {
		argument_error();
		return 1;
	}

	// setup signal handler
#ifdef PION_WIN32
	SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
#else
	signal(SIGINT, handle_signal);
#endif

	// initialize log system (use simple configuration)
	PionLogger main_log(PION_GET_LOGGER("PionServiceTest"));
	PionLogger pion_log(PION_GET_LOGGER("Pion"));
	PION_LOG_SETLEVEL_DEBUG(main_log);
	PION_LOG_SETLEVEL_DEBUG(pion_log);
	PION_LOG_CONFIG_BASIC;

	try {
		// add the Pion plug-ins installation directory to our path
		try { PionNet::addPluginDirectory(PION_PLUGINS_DIRECTORY); }
		catch (PionPlugin::DirectoryNotFoundException&) {
			PION_LOG_WARN(main_log, "Default plug-ins directory does not exist: "
				<< PION_PLUGINS_DIRECTORY);
		}

		// create a server for HTTP & add the Hello Service
		HTTPServerPtr http_server(PionNet::addHTTPServer(port));

		if (ssl_flag) {
#ifdef PION_HAVE_SSL
			// configure server for SSL
			http_server->setSSLFlag(true);
			boost::asio::ssl::context& ssl_context = http_server->getSSLContext();
			ssl_context.set_options(boost::asio::ssl::context::default_workarounds
									| boost::asio::ssl::context::no_sslv2
									| boost::asio::ssl::context::single_dh_use);
			ssl_context.use_certificate_file(ssl_pem_file, boost::asio::ssl::context::pem);
			ssl_context.use_private_key_file(ssl_pem_file, boost::asio::ssl::context::pem);
			PION_LOG_INFO(main_log, "SSL support enabled using key file: " << ssl_pem_file);
#else
			PION_LOG_ERROR(main_log, "SSL support is not enabled");
#endif
		}

		if (service_config_file.empty()) {
			// load a single web service using the command line arguments
			http_server->loadService(resource_name, service_name);

			// set web service options if any are defined
			for (ServiceOptionsType::iterator i = service_options.begin();
				 i != service_options.end(); ++i)
			{
				http_server->setServiceOption(resource_name, i->first, i->second);
			}
		} else {
			// load services using the configuration file
			http_server->loadServiceConfig(service_config_file);
		}

		// startup pion
		PionNet::startup();

		// run until stopped
		PionNet::join();

	} catch (std::exception& e) {
		PION_LOG_FATAL(main_log, e.what());
	}

	return 0;
}
<commit_msg>Added the directory of the current executable to the plug-in search path, to enable running from the tests directory.<commit_after>// ------------------------------------------------------------------
// pion-net: a C++ framework for building lightweight HTTP interfaces
// ------------------------------------------------------------------
// Copyright (C) 2007 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file COPYING or copy at http://www.boost.org/LICENSE_1_0.txt
//

#include <boost/bind.hpp>
#include <pion/net/PionNet.hpp>
#include <iostream>
#include <vector>
#ifndef PION_WIN32
	#include <signal.h>
#endif

// these are used only when linking to static web service libraries
// #ifdef PION_STATIC_LINKING
PION_DECLARE_PLUGIN(EchoService)
PION_DECLARE_PLUGIN(FileService)
PION_DECLARE_PLUGIN(HelloService)
PION_DECLARE_PLUGIN(LogService)
PION_DECLARE_PLUGIN(CookieService)

using namespace std;
using namespace pion;
using namespace pion::net;

/// stops Pion when it receives signals
#ifdef PION_WIN32
BOOL WINAPI console_ctrl_handler(DWORD ctrl_type)
{
	switch(ctrl_type) {
		case CTRL_C_EVENT:
		case CTRL_BREAK_EVENT:
		case CTRL_CLOSE_EVENT:
		case CTRL_SHUTDOWN_EVENT:
			PionNet::shutdown();
			return TRUE;
		default:
			return FALSE;
	}
}
#else
void handle_signal(int sig)
{
	PionNet::shutdown();
}
#endif

/// displays an error message if the arguments are invalid
void argument_error(void)
{
	std::cerr << "usage:   PionServiceTest [OPTIONS] RESOURCE WEBSERVICE" << std::endl
		      << "         PionServiceTest [OPTIONS] -c SERVICE_CONFIG_FILE" << std::endl
			  << "options: [-ssl PEM_FILE] [-p PORT] [-d SERVICE_PLUGINS_DIR] [-o OPTION=VALUE]" << std::endl;
}

/// main control function
int main (int argc, char *argv[])
{
	static const unsigned int DEFAULT_PORT = 8080;

	// used to keep track of web service name=value options
	typedef std::vector<std::pair<std::string, std::string> >	ServiceOptionsType;
	ServiceOptionsType service_options;

	// parse command line: determine port number, RESOURCE and WEBSERVICE
	unsigned int port = DEFAULT_PORT;
	std::string service_config_file;
	std::string resource_name;
	std::string service_name;
	std::string ssl_pem_file;
	bool ssl_flag = false;

	for (int argnum=1; argnum < argc; ++argnum) {
		if (argv[argnum][0] == '-') {
			if (argv[argnum][1] == 'p' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				++argnum;
				port = strtoul(argv[argnum], 0, 10);
				if (port == 0) port = DEFAULT_PORT;
			} else if (argv[argnum][1] == 'c' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				service_config_file = argv[++argnum];
			} else if (argv[argnum][1] == 'd' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				// add the service plug-ins directory to the search path
				try { PionNet::addPluginDirectory(argv[++argnum]); }
				catch (PionPlugin::DirectoryNotFoundException&) {
					std::cerr << "PionServiceTest: Web service plug-ins directory does not exist: "
						<< argv[argnum] << std::endl;
					return 1;
				}
			} else if (argv[argnum][1] == 'o' && argv[argnum][2] == '\0' && argnum+1 < argc) {
				std::string option_name(argv[++argnum]);
				std::string::size_type pos = option_name.find('=');
				if (pos == std::string::npos) {
					argument_error();
					return 1;
				}
				std::string option_value(option_name, pos + 1);
				option_name.resize(pos);
				service_options.push_back( std::make_pair(option_name, option_value) );
			} else if (argv[argnum][1] == 's' && argv[argnum][2] == 's' &&
					   argv[argnum][3] == 'l' && argv[argnum][4] == '\0' && argnum+1 < argc) {
				ssl_flag = true;
				ssl_pem_file = argv[++argnum];
			} else {
				argument_error();
				return 1;
			}
		} else if (argnum+2 == argc) {
			// second to last argument = RESOURCE
			resource_name = argv[argnum];
		} else if (argnum+1 == argc) {
			// last argument = WEBSERVICE
			service_name = argv[argnum];
		} else {
			argument_error();
			return 1;
		}
	}

	if (service_config_file.empty() && (resource_name.empty() || service_name.empty())) {
		argument_error();
		return 1;
	}

	// setup signal handler
#ifdef PION_WIN32
	SetConsoleCtrlHandler(console_ctrl_handler, TRUE);
#else
	signal(SIGINT, handle_signal);
#endif

	// initialize log system (use simple configuration)
	PionLogger main_log(PION_GET_LOGGER("PionServiceTest"));
	PionLogger pion_log(PION_GET_LOGGER("Pion"));
	PION_LOG_SETLEVEL_DEBUG(main_log);
	PION_LOG_SETLEVEL_DEBUG(pion_log);
	PION_LOG_CONFIG_BASIC;

	try {
		// add the Pion plug-ins installation directory to our path
		try { PionNet::addPluginDirectory(PION_PLUGINS_DIRECTORY); }
		catch (PionPlugin::DirectoryNotFoundException&) {
			PION_LOG_WARN(main_log, "Default plug-ins directory does not exist: "
				<< PION_PLUGINS_DIRECTORY);
		}

		// add the directory of the program we're running to our path
		try { PionNet::addPluginDirectory(boost::filesystem::path(argv[0]).branch_path().string()); }
		catch (PionPlugin::DirectoryNotFoundException&) {
			PION_LOG_WARN(main_log, "Directory of current executable does not exist: "
				<< boost::filesystem::path(argv[0]).branch_path());
		}

		// create a server for HTTP & add the Hello Service
		HTTPServerPtr http_server(PionNet::addHTTPServer(port));

		if (ssl_flag) {
#ifdef PION_HAVE_SSL
			// configure server for SSL
			http_server->setSSLFlag(true);
			boost::asio::ssl::context& ssl_context = http_server->getSSLContext();
			ssl_context.set_options(boost::asio::ssl::context::default_workarounds
									| boost::asio::ssl::context::no_sslv2
									| boost::asio::ssl::context::single_dh_use);
			ssl_context.use_certificate_file(ssl_pem_file, boost::asio::ssl::context::pem);
			ssl_context.use_private_key_file(ssl_pem_file, boost::asio::ssl::context::pem);
			PION_LOG_INFO(main_log, "SSL support enabled using key file: " << ssl_pem_file);
#else
			PION_LOG_ERROR(main_log, "SSL support is not enabled");
#endif
		}

		if (service_config_file.empty()) {
			// load a single web service using the command line arguments
			http_server->loadService(resource_name, service_name);

			// set web service options if any are defined
			for (ServiceOptionsType::iterator i = service_options.begin();
				 i != service_options.end(); ++i)
			{
				http_server->setServiceOption(resource_name, i->first, i->second);
			}
		} else {
			// load services using the configuration file
			http_server->loadServiceConfig(service_config_file);
		}

		// startup pion
		PionNet::startup();

		// run until stopped
		PionNet::join();

	} catch (std::exception& e) {
		PION_LOG_FATAL(main_log, e.what());
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <unistd.h>
#include <regex.h>
#include <time.h>

#include "xalt_utils.h"
#include "xalt_config.h"
#include "xalt_regex.h"
#include "Options.h"

#define DATESZ 100

bool path2module(const char* path, Table& rmapT, char* module_name, int module_name_sz)
{
  std::string p(path);
  bool found = false;

  while(1)
    {
      std::string::size_type idx = p.rfind('/');
      if (idx == std::string::npos)
        break;

      p.erase(idx, std::string::npos);
      Table::const_iterator got = rmapT.find(p);
      if (got != rmapT.end())
        {
          found   = true;
          int len = (*got).second.size();
          if (len > (module_name_sz - 1))
            len = module_name_sz - 1;
          memcpy(module_name, (*got).second.c_str(),len);
          module_name[len] = '\0';
          break;
        }
    }
  return found;
}

FILE* xalt_file_open(const char* name)
{
  FILE*       fp           = NULL;
  const char* xalt_etc_dir = getenv("XALT_ETC_DIR");
  std::string dirNm;
  std::string fn;

  fp = fopen(name,"r");
  if (fp)
    return fp;

  if (xalt_etc_dir == NULL)
    xalt_etc_dir = XALT_ETC_DIR;

  const char* start = xalt_etc_dir;
  bool        done  = false;
  while(!done)
    {
      char * p = strchr((char *) start,':');
      if (p)
        dirNm.assign(start, p - start);
      else
        {
          dirNm.assign(start);
          done = true;
        }

      fn.assign(dirNm);
      fn += "/";
      fn += name;
      fp  = fopen(fn.c_str(), "r");
      if (fp)
        break;

      start = ++p;
    }
  return fp;
}

FILE* xalt_json_file_open(std::string& rmapD, const char* name)
{
  FILE*              fp     = NULL;
  static const char *extA[] = {".json", ".old.json"};
  static int         nExt   = sizeof(extA)/sizeof(extA[0]);
  std::string        dirNm;
  std::string        fn;

  // First look in rmapD if it has value.
  if (rmapD.size() > 0)
    {
      for (int i = 0; i < nExt; ++i)
        {
          fn.assign(rmapD);
          fn += "/";
          fn += name;
          fn += extA[i];
          fp  = fopen(fn.c_str(), "r");
          if (fp)
            return fp;
        }
    }

  // Otherwise search directories in XALT_ETC_DIR

  const char* xalt_etc_dir = getenv("XALT_ETC_DIR");
  if (xalt_etc_dir == NULL)
    xalt_etc_dir = XALT_ETC_DIR;

  const char* start = xalt_etc_dir;
  bool        done  = false;
  while(!done)
    {
      char * p = strchr((char *) start,':');
      if (p)
        dirNm.assign(start, p - start);
      else
        {
          dirNm.assign(start);
          done = true;
        }

      for (int i = 0; i < nExt; ++i)
        {
          fn.assign(dirNm);
          fn += "/";
          fn += name;
          fn += extA[i];
          fp  = fopen(fn.c_str(), "r");
          if (fp)
            break;
        }
      start = ++p;
    }
  return fp;
}

#define BITS_IN_int    (sizeof (int)*CHAR_BIT)
#define THREE_QUARTERS ((int) ((BITS_IN_int * 3) / 4))
#define ONE_EIGHTH     ((int) (BITS_IN_int / 8))
#define HIGH_BITS      ( ~ ((unsigned int) (~0) >> ONE_EIGHTH ))

unsigned int hashStr(const char * string)
{
  unsigned int hash_value, i;
  for ( hash_value = 0; *string; ++string)
    {
      hash_value = (hash_value << ONE_EIGHTH) + *string;
      if ( (i = hash_value & HIGH_BITS ) != 0)
        hash_value = (hash_value ^ (i >> THREE_QUARTERS )) & ~HIGH_BITS;
    }
  return hash_value;
}

void build_resultDir(std::string& resultDir, const char *kind, const char* transmission, const char* uuid)
{
  char* c_home = getenv("HOME");
  char* c_user = getenv("USER");

  if (c_home != NULL && c_user != NULL )
    {
      const char * xalt_file_prefix = getenv("XALT_FILE_PREFIX");
      if (xalt_file_prefix == NULL)
        xalt_file_prefix = XALT_FILE_PREFIX;
      if (strcasecmp(xalt_file_prefix,"USE_HOME") == 0)
        {
          resultDir.assign(c_home);
          resultDir.append("/.xalt.d/");
          if (strcasecmp(transmission,"file_separate_dirs") == 0)
            {
              resultDir.append(kind);
              resultDir.append("/");
            }
        }
      else
        {
          resultDir.assign(xalt_file_prefix);
          resultDir.append("/");
          if (strcasecmp(transmission,"file_separate_dirs") == 0)
            {
              resultDir.append(kind);
              resultDir.append("/");
            }
          char * hashDir = NULL;
          long   hashV   = std::stol(&uuid[29]) % XALT_PRIME_NUMBER

          asprintf(&hashDir, XALT_PRIME_FMT "/", hashV);
          resultDir.append(hashDir);
          free(hashDir);
        }
    }
}

void build_resultFn(std::string& resultFn, double start, const char* syshost, const char* uuid, const char *kind,
                    const char* suffix)
{
  char dateStr[DATESZ];
  char* c_home = getenv("HOME");
  char* c_user = getenv("USER");

  if (c_home != NULL && c_user != NULL )
    {
      double frac  = start - floor(start);
      time_t  time = start;
      strftime(dateStr, DATESZ, "%Y_%m_%d_%H_%M_%S",localtime(&time));

      std::ostringstream sstream;
      sstream << kind   << "." << syshost << "." << dateStr
              << "_" << std::setfill('0') << std::setw(4) << (int) (frac*10000.0)
              << "." << c_user << suffix << "."    << uuid  << ".json";

      resultFn = sstream.str();
    }
}
<commit_msg>use statc_cast<int>() instead of (int) when converting the long value to an int when computing resultDir<commit_after>#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <unistd.h>
#include <regex.h>
#include <time.h>

#include "xalt_utils.h"
#include "xalt_config.h"
#include "xalt_regex.h"
#include "Options.h"

#define DATESZ 100

bool path2module(const char* path, Table& rmapT, char* module_name, int module_name_sz)
{
  std::string p(path);
  bool found = false;

  while(1)
    {
      std::string::size_type idx = p.rfind('/');
      if (idx == std::string::npos)
        break;

      p.erase(idx, std::string::npos);
      Table::const_iterator got = rmapT.find(p);
      if (got != rmapT.end())
        {
          found   = true;
          int len = (*got).second.size();
          if (len > (module_name_sz - 1))
            len = module_name_sz - 1;
          memcpy(module_name, (*got).second.c_str(),len);
          module_name[len] = '\0';
          break;
        }
    }
  return found;
}

FILE* xalt_file_open(const char* name)
{
  FILE*       fp           = NULL;
  const char* xalt_etc_dir = getenv("XALT_ETC_DIR");
  std::string dirNm;
  std::string fn;

  fp = fopen(name,"r");
  if (fp)
    return fp;

  if (xalt_etc_dir == NULL)
    xalt_etc_dir = XALT_ETC_DIR;

  const char* start = xalt_etc_dir;
  bool        done  = false;
  while(!done)
    {
      char * p = strchr((char *) start,':');
      if (p)
        dirNm.assign(start, p - start);
      else
        {
          dirNm.assign(start);
          done = true;
        }

      fn.assign(dirNm);
      fn += "/";
      fn += name;
      fp  = fopen(fn.c_str(), "r");
      if (fp)
        break;

      start = ++p;
    }
  return fp;
}

FILE* xalt_json_file_open(std::string& rmapD, const char* name)
{
  FILE*              fp     = NULL;
  static const char *extA[] = {".json", ".old.json"};
  static int         nExt   = sizeof(extA)/sizeof(extA[0]);
  std::string        dirNm;
  std::string        fn;

  // First look in rmapD if it has value.
  if (rmapD.size() > 0)
    {
      for (int i = 0; i < nExt; ++i)
        {
          fn.assign(rmapD);
          fn += "/";
          fn += name;
          fn += extA[i];
          fp  = fopen(fn.c_str(), "r");
          if (fp)
            return fp;
        }
    }

  // Otherwise search directories in XALT_ETC_DIR

  const char* xalt_etc_dir = getenv("XALT_ETC_DIR");
  if (xalt_etc_dir == NULL)
    xalt_etc_dir = XALT_ETC_DIR;

  const char* start = xalt_etc_dir;
  bool        done  = false;
  while(!done)
    {
      char * p = strchr((char *) start,':');
      if (p)
        dirNm.assign(start, p - start);
      else
        {
          dirNm.assign(start);
          done = true;
        }

      for (int i = 0; i < nExt; ++i)
        {
          fn.assign(dirNm);
          fn += "/";
          fn += name;
          fn += extA[i];
          fp  = fopen(fn.c_str(), "r");
          if (fp)
            break;
        }
      start = ++p;
    }
  return fp;
}

#define BITS_IN_int    (sizeof (int)*CHAR_BIT)
#define THREE_QUARTERS ((int) ((BITS_IN_int * 3) / 4))
#define ONE_EIGHTH     ((int) (BITS_IN_int / 8))
#define HIGH_BITS      ( ~ ((unsigned int) (~0) >> ONE_EIGHTH ))

unsigned int hashStr(const char * string)
{
  unsigned int hash_value, i;
  for ( hash_value = 0; *string; ++string)
    {
      hash_value = (hash_value << ONE_EIGHTH) + *string;
      if ( (i = hash_value & HIGH_BITS ) != 0)
        hash_value = (hash_value ^ (i >> THREE_QUARTERS )) & ~HIGH_BITS;
    }
  return hash_value;
}

void build_resultDir(std::string& resultDir, const char *kind, const char* transmission, const char* uuid)
{
  char* c_home = getenv("HOME");
  char* c_user = getenv("USER");

  if (c_home != NULL && c_user != NULL )
    {
      const char * xalt_file_prefix = getenv("XALT_FILE_PREFIX");
      if (xalt_file_prefix == NULL)
        xalt_file_prefix = XALT_FILE_PREFIX;
      if (strcasecmp(xalt_file_prefix,"USE_HOME") == 0)
        {
          resultDir.assign(c_home);
          resultDir.append("/.xalt.d/");
          if (strcasecmp(transmission,"file_separate_dirs") == 0)
            {
              resultDir.append(kind);
              resultDir.append("/");
            }
        }
      else
        {
          resultDir.assign(xalt_file_prefix);
          resultDir.append("/");
          if (strcasecmp(transmission,"file_separate_dirs") == 0)
            {
              resultDir.append(kind);
              resultDir.append("/");
            }
          char * hashDir = NULL;
          int    hashV   = static_cast<int>(std::stol(&uuid[29],0, 16) % XALT_PRIME_NUMBER);

          asprintf(&hashDir, XALT_PRIME_FMT "/", hashV);
          resultDir.append(hashDir);
          free(hashDir);
        }
    }
}

void build_resultFn(std::string& resultFn, double start, const char* syshost, const char* uuid, const char *kind,
                    const char* suffix)
{
  char dateStr[DATESZ];
  char* c_home = getenv("HOME");
  char* c_user = getenv("USER");

  if (c_home != NULL && c_user != NULL )
    {
      double frac  = start - floor(start);
      time_t  time = start;
      strftime(dateStr, DATESZ, "%Y_%m_%d_%H_%M_%S",localtime(&time));

      std::ostringstream sstream;
      sstream << kind   << "." << syshost << "." << dateStr
              << "_" << std::setfill('0') << std::setw(4) << (int) (frac*10000.0)
              << "." << c_user << suffix << "."    << uuid  << ".json";

      resultFn = sstream.str();
    }
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2010  Collabora Multimedia.
      @author Mauricio Piacentini <mauricio.piacentini@collabora.co.uk>

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "qgsttest.h"
#include <QGst/Buffer>
#include <QGst/Caps>

class BufferTest : public QGstTest
{
    Q_OBJECT
private Q_SLOTS:
    void simpleTest();
    void flagsTest();
    void copyTest();
};

void BufferTest::simpleTest()
{
    QGst::BufferPtr buffer = QGst::Buffer::create(10);

    QCOMPARE(buffer->size(), (quint32) 10);
    QVERIFY(buffer->data());
}

void BufferTest::flagsTest()
{
    QGst::BufferPtr buffer = QGst::Buffer::create(10);
    QGst::BufferFlags flags(QGst::BufferFlagLive & QGst::BufferFlagDiscont);
    buffer->setFlags(flags);

    QGst::BufferFlags flags2 = buffer->flags();
    QCOMPARE(flags, flags2);

    QGst::BufferFlags flags3(QGst::BufferFlagLive);
    QVERIFY(flags2!=flags3);
}

void BufferTest::copyTest()
{
    QGst::BufferPtr buffer = QGst::Buffer::create(10);
    QGst::BufferFlags flags(QGst::BufferFlagLive & QGst::BufferFlagDiscont);
    buffer->setFlags(flags);

    QGst::BufferPtr buffer2 = buffer->copy();

    QCOMPARE(buffer->size(), buffer2->size());
    QCOMPARE(buffer->decodingTimeStamp(), buffer2->decodingTimeStamp());
    QCOMPARE(buffer->presentationTimeStamp(), buffer2->presentationTimeStamp());
    QCOMPARE(buffer->duration(), buffer2->duration());

    QGst::BufferFlags flags2(QGst::BufferFlagDiscont);
    buffer2->setFlags(flags2);

    QVERIFY(buffer->flags() != buffer2->flags());
}

QTEST_APPLESS_MAIN(BufferTest)

#include "moc_qgsttest.cpp"
#include "buffertest.moc"

<commit_msg>tests/auto/buffertest.cpp Replace data call with peekMemory<commit_after>/*
    Copyright (C) 2010  Collabora Multimedia.
      @author Mauricio Piacentini <mauricio.piacentini@collabora.co.uk>

    This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published
    by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "qgsttest.h"
#include <QGst/Buffer>
#include <QGst/Caps>

class BufferTest : public QGstTest
{
    Q_OBJECT
private Q_SLOTS:
    void simpleTest();
    void flagsTest();
    void copyTest();
};

void BufferTest::simpleTest()
{
    QGst::BufferPtr buffer = QGst::Buffer::create(10);

    QCOMPARE(buffer->size(), (quint32) 10);
    QVERIFY(buffer->peekMemory(0));
}

void BufferTest::flagsTest()
{
    QGst::BufferPtr buffer = QGst::Buffer::create(10);
    QGst::BufferFlags flags(QGst::BufferFlagLive & QGst::BufferFlagDiscont);
    buffer->setFlags(flags);

    QGst::BufferFlags flags2 = buffer->flags();
    QCOMPARE(flags, flags2);

    QGst::BufferFlags flags3(QGst::BufferFlagLive);
    QVERIFY(flags2!=flags3);
}

void BufferTest::copyTest()
{
    QGst::BufferPtr buffer = QGst::Buffer::create(10);
    QGst::BufferFlags flags(QGst::BufferFlagLive & QGst::BufferFlagDiscont);
    buffer->setFlags(flags);

    QGst::BufferPtr buffer2 = buffer->copy();

    QCOMPARE(buffer->size(), buffer2->size());
    QCOMPARE(buffer->decodingTimeStamp(), buffer2->decodingTimeStamp());
    QCOMPARE(buffer->presentationTimeStamp(), buffer2->presentationTimeStamp());
    QCOMPARE(buffer->duration(), buffer2->duration());

    QGst::BufferFlags flags2(QGst::BufferFlagDiscont);
    buffer2->setFlags(flags2);

    QVERIFY(buffer->flags() != buffer2->flags());
}

QTEST_APPLESS_MAIN(BufferTest)

#include "moc_qgsttest.cpp"
#include "buffertest.moc"

<|endoftext|>