<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2014 VoltDB Inc.
 *
 * This program 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.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <boost/lexical_cast.hpp>
#include "common/MiscUtil.h"
#include "common/TupleOutputStream.h"
#include "common/TupleOutputStreamProcessor.h"
#include "storage/ElasticIndexReadContext.h"
#include "storage/persistenttable.h"
#include "logging/LogManager.h"

namespace voltdb
{

/**
 * Constructor.
 * Parse and hold onto an "XXX:YYY" range predicate locally.
 */
ElasticIndexReadContext::ElasticIndexReadContext(
        PersistentTable &table,
        PersistentTableSurgeon &surgeon,
        int32_t partitionId,
        TupleSerializer &serializer,
        const std::vector<std::string> &predicateStrings) :
    TableStreamerContext(table, surgeon, partitionId, serializer),
    m_predicateStrings(predicateStrings),
    m_materialized(false)
{}

/**
 * Destructor.
 */
ElasticIndexReadContext::~ElasticIndexReadContext()
{}

/**
 * Activation handler.
 */
TableStreamerContext::ActivationReturnCode
ElasticIndexReadContext::handleActivation(TableStreamType streamType)
{
    if (streamType != TABLE_STREAM_ELASTIC_INDEX_READ) {
        return ACTIVATION_UNSUPPORTED;
    }

    if (!m_surgeon.hasIndex()) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_INFO, "Activation of elastic index for read did not occur because the table reports no index exists yet.");
        return ACTIVATION_FAILED;
    }

    if (!m_surgeon.isIndexingComplete()) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, "Activation of elastic index for read failed because index generation is not complete yet.");
        return ACTIVATION_FAILED;
    }

    ElasticIndexHashRange range;
    if (!parseHashRange(m_predicateStrings, range)) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, "Activation failed because parsing the hash range showed a conflict.");
        return ACTIVATION_FAILED;
    }

    m_iter = m_surgeon.getIndexTupleRangeIterator(range);
    return ACTIVATION_SUCCEEDED;
}

/**
 * Deactivation handler.
 */
bool ElasticIndexReadContext::handleDeactivation(TableStreamType streamType)
{
    if (streamType == TABLE_STREAM_ELASTIC_INDEX_READ) {
        // This context is no longer needed.
        return false;
    }

    // Fall through for other unsupported stream types.
    throwFatalException("Unexpected stream type %d in handleDeactivation().", static_cast<int>(streamType))
    return false;
}

/*
 * Serialize to output stream. Receive a list of streams, but expect only 1.
 * Return 1 if tuples remain, 0 if done, or TABLE_STREAM_SERIALIZATION_ERROR on error.
 */
int64_t ElasticIndexReadContext::handleStreamMore(
        TupleOutputStreamProcessor &outputStreams,
        std::vector<int> &retPositions)
{
    // Default to success.
    int64_t remaining = 1;

    // Check that activation happened.
    if (m_iter == NULL) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR,
            "Attempted to begin serialization without activating the context.");
        remaining = TABLE_STREAM_SERIALIZATION_ERROR;
    }

    // Need to initialize the output stream list.
    else if (outputStreams.size() != 1) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR,
            "serializeMore() expects exactly one output stream.");
        remaining = TABLE_STREAM_SERIALIZATION_ERROR;
    }

    else {
        // Anything left?
        TableTuple tuple;
        if (!m_iter->next(tuple)) {
            remaining = 0;
        }

        // More tuples are available - continue streaming and iterating.
        if (remaining != 0) {
            outputStreams.open(getTable(),
                               getMaxTupleLength(),
                               getPartitionId(),
                               getPredicates(),
                               getPredicateDeleteFlags());

            // Set to true to break out of the loop after the tuples dry up
            // or the byte count threshold is hit.
            bool yield = false;
            while (!yield) {
                // If the tuple is pending delete, it's held on by COW but
                // shouldn't be accessable anymore. So don't write it to the
                // output.
                if (!tuple.isPendingDelete()) {
                    // Write the tuple.
                    yield = outputStreams.writeRow(getSerializer(), tuple);
                } else {
                    throwFatalException("Materializing a deleted tuple from the elastic context.");
                }

                if (!yield) {
                    if (!m_iter->next(tuple)) {
                        yield = true;
                        remaining = 0;
                    }
                }
            }

            // Need to close the output streams and insert row counts.
            outputStreams.close();
        }

        /**
         * Un-comment this section when you need to do more detailed forensics
         * on balance partition transactions. Don't forget to include both
         * <string> and <sstream>
         */
        /*
        std::ostringstream os;
        ElasticIndexHashRange range = m_iter->range();
        os << "Moved " << outputStreams.at(0).getSerializedRowCount() << " rows for range ["
           << range.getLowerBound() << ", " << range.getUpperBound()
           << "], elastic index size is " << m_surgeon.indexSize();

        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_INFO, os.str().c_str());
         */

        // If more was streamed copy current position for return (exactly one stream).
        retPositions.push_back((int)outputStreams.at(0).position());

        // After the index is completely consumed delete index entries and referenced tuples.
        if (remaining <= 0) {
            m_materialized = true;
            deleteStreamedTuples();
        }
    }

    return remaining;
}

/**
 * Parse and validate the hash range.
 */
bool ElasticIndexReadContext::parseHashRange(
        const std::vector<std::string> &predicateStrings,
        ElasticIndexHashRange &rangeOut)
{
    bool success = false;
    if (predicateStrings.size() != 1) {
        char errMsg[1024 * 16];
        snprintf(errMsg, 1024 * 16,
                 "Too many ElasticIndexReadContext predicates (>1): %ld",
                 predicateStrings.size());
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, errMsg);
    }
    else {
        std::vector<std::string> rangeStrings = MiscUtil::splitToTwoString(predicateStrings.at(0), ':');
        if (rangeStrings.size() == 2) {
            try {
                rangeOut = ElasticIndexHashRange(boost::lexical_cast<int32_t>(rangeStrings[0]),
                                                 boost::lexical_cast<int32_t>(rangeStrings[1]));
                success = true;
            }
            catch(boost::bad_lexical_cast) {
                char errMsg[1024 * 16];
                snprintf(errMsg, 1024 * 16,
                         "Unable to parse ElasticIndexReadContext predicate \"%s\".",
                         predicateStrings.at(0).c_str());
                LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, errMsg);
            }
        } else {
            LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, "Hash range did not have two entries");
        }
    }
    return success;
}

/**
 * Clean up after consuming indexed tuples.
 */
void ElasticIndexReadContext::deleteStreamedTuples()
{
    // Delete the indexed tuples that were streamed.
    // Undo token release will cause the index to delete the corresponding items
    // via notifications.
    m_iter->reset();
    TableTuple tuple;
    while (m_iter->next(tuple)) {
        if (!tuple.isPendingDelete()) {
            m_surgeon.deleteTuple(tuple);
        }
    }
}

} // namespace voltdb
<commit_msg>For ENG-6653, don't DR data deleted by elastic rebalance.<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2014 VoltDB Inc.
 *
 * This program 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.
 *
 * 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <boost/lexical_cast.hpp>
#include "common/MiscUtil.h"
#include "common/TupleOutputStream.h"
#include "common/TupleOutputStreamProcessor.h"
#include "storage/ElasticIndexReadContext.h"
#include "storage/persistenttable.h"
#include "logging/LogManager.h"

namespace voltdb
{

/**
 * Constructor.
 * Parse and hold onto an "XXX:YYY" range predicate locally.
 */
ElasticIndexReadContext::ElasticIndexReadContext(
        PersistentTable &table,
        PersistentTableSurgeon &surgeon,
        int32_t partitionId,
        TupleSerializer &serializer,
        const std::vector<std::string> &predicateStrings) :
    TableStreamerContext(table, surgeon, partitionId, serializer),
    m_predicateStrings(predicateStrings),
    m_materialized(false)
{}

/**
 * Destructor.
 */
ElasticIndexReadContext::~ElasticIndexReadContext()
{}

/**
 * Activation handler.
 */
TableStreamerContext::ActivationReturnCode
ElasticIndexReadContext::handleActivation(TableStreamType streamType)
{
    if (streamType != TABLE_STREAM_ELASTIC_INDEX_READ) {
        return ACTIVATION_UNSUPPORTED;
    }

    if (!m_surgeon.hasIndex()) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_INFO, "Activation of elastic index for read did not occur because the table reports no index exists yet.");
        return ACTIVATION_FAILED;
    }

    if (!m_surgeon.isIndexingComplete()) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, "Activation of elastic index for read failed because index generation is not complete yet.");
        return ACTIVATION_FAILED;
    }

    ElasticIndexHashRange range;
    if (!parseHashRange(m_predicateStrings, range)) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, "Activation failed because parsing the hash range showed a conflict.");
        return ACTIVATION_FAILED;
    }

    m_iter = m_surgeon.getIndexTupleRangeIterator(range);
    return ACTIVATION_SUCCEEDED;
}

/**
 * Deactivation handler.
 */
bool ElasticIndexReadContext::handleDeactivation(TableStreamType streamType)
{
    if (streamType == TABLE_STREAM_ELASTIC_INDEX_READ) {
        // This context is no longer needed.
        return false;
    }

    // Fall through for other unsupported stream types.
    throwFatalException("Unexpected stream type %d in handleDeactivation().", static_cast<int>(streamType))
    return false;
}

/*
 * Serialize to output stream. Receive a list of streams, but expect only 1.
 * Return 1 if tuples remain, 0 if done, or TABLE_STREAM_SERIALIZATION_ERROR on error.
 */
int64_t ElasticIndexReadContext::handleStreamMore(
        TupleOutputStreamProcessor &outputStreams,
        std::vector<int> &retPositions)
{
    // Default to success.
    int64_t remaining = 1;

    // Check that activation happened.
    if (m_iter == NULL) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR,
            "Attempted to begin serialization without activating the context.");
        remaining = TABLE_STREAM_SERIALIZATION_ERROR;
    }

    // Need to initialize the output stream list.
    else if (outputStreams.size() != 1) {
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR,
            "serializeMore() expects exactly one output stream.");
        remaining = TABLE_STREAM_SERIALIZATION_ERROR;
    }

    else {
        // Anything left?
        TableTuple tuple;
        if (!m_iter->next(tuple)) {
            remaining = 0;
        }

        // More tuples are available - continue streaming and iterating.
        if (remaining != 0) {
            outputStreams.open(getTable(),
                               getMaxTupleLength(),
                               getPartitionId(),
                               getPredicates(),
                               getPredicateDeleteFlags());

            // Set to true to break out of the loop after the tuples dry up
            // or the byte count threshold is hit.
            bool yield = false;
            while (!yield) {
                // If the tuple is pending delete, it's held on by COW but
                // shouldn't be accessable anymore. So don't write it to the
                // output.
                if (!tuple.isPendingDelete()) {
                    // Write the tuple.
                    yield = outputStreams.writeRow(getSerializer(), tuple);
                } else {
                    throwFatalException("Materializing a deleted tuple from the elastic context.");
                }

                if (!yield) {
                    if (!m_iter->next(tuple)) {
                        yield = true;
                        remaining = 0;
                    }
                }
            }

            // Need to close the output streams and insert row counts.
            outputStreams.close();
        }

        /**
         * Un-comment this section when you need to do more detailed forensics
         * on balance partition transactions. Don't forget to include both
         * <string> and <sstream>
         */
        /*
        std::ostringstream os;
        ElasticIndexHashRange range = m_iter->range();
        os << "Moved " << outputStreams.at(0).getSerializedRowCount() << " rows for range ["
           << range.getLowerBound() << ", " << range.getUpperBound()
           << "], elastic index size is " << m_surgeon.indexSize();

        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_INFO, os.str().c_str());
         */

        // If more was streamed copy current position for return (exactly one stream).
        retPositions.push_back((int)outputStreams.at(0).position());

        // After the index is completely consumed delete index entries and referenced tuples.
        if (remaining <= 0) {
            m_materialized = true;
            deleteStreamedTuples();
        }
    }

    return remaining;
}

/**
 * Parse and validate the hash range.
 */
bool ElasticIndexReadContext::parseHashRange(
        const std::vector<std::string> &predicateStrings,
        ElasticIndexHashRange &rangeOut)
{
    bool success = false;
    if (predicateStrings.size() != 1) {
        char errMsg[1024 * 16];
        snprintf(errMsg, 1024 * 16,
                 "Too many ElasticIndexReadContext predicates (>1): %ld",
                 predicateStrings.size());
        LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, errMsg);
    }
    else {
        std::vector<std::string> rangeStrings = MiscUtil::splitToTwoString(predicateStrings.at(0), ':');
        if (rangeStrings.size() == 2) {
            try {
                rangeOut = ElasticIndexHashRange(boost::lexical_cast<int32_t>(rangeStrings[0]),
                                                 boost::lexical_cast<int32_t>(rangeStrings[1]));
                success = true;
            }
            catch(boost::bad_lexical_cast) {
                char errMsg[1024 * 16];
                snprintf(errMsg, 1024 * 16,
                         "Unable to parse ElasticIndexReadContext predicate \"%s\".",
                         predicateStrings.at(0).c_str());
                LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, errMsg);
            }
        } else {
            LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, "Hash range did not have two entries");
        }
    }
    return success;
}

/**
 * Clean up after consuming indexed tuples.
 */
void ElasticIndexReadContext::deleteStreamedTuples()
{
    // Delete the indexed tuples that were streamed.
    // Undo token release will cause the index to delete the corresponding items
    // via notifications.
    ExecutorContext::getExecutorContext()->drStream()->m_enabled = false;
    //Not unused, but GCC doesn't think a destructor counts as use
    class DisableDRGuard {
    public:
        ~DisableDRGuard() {
            ExecutorContext::getExecutorContext()->drStream()->m_enabled = true;
        }
    } __attribute__((unused)) guard;
    m_iter->reset();
    TableTuple tuple;
    while (m_iter->next(tuple)) {
        if (!tuple.isPendingDelete()) {
            m_surgeon.deleteTuple(tuple);
        }
    }
}

} // namespace voltdb
<|endoftext|>


<commit_before>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "reader.h"
#include "reader/impl.h"

#ifndef DISABLE_JSONLD
#include "reader/jsonld.h"
#endif

#ifndef DISABLE_NQUADS
#include "reader/nquads.h"
#endif

#ifndef DISABLE_TRIX
#include "reader/trix.h"
#endif

#ifdef HAVE_LIBRAPTOR2
#include "raptor.h"
#include "reader/raptor.h"
#endif

#ifdef HAVE_LIBSERD
#include "reader/serd.h"
#endif

#include "format.h"
#include "quad.h"
#include "term.h"
#include "triple.h"

#include <cassert>    /* for assert() */
#include <cstring>    /* for std::strcmp() */
#include <functional> /* for std::function */
#include <stdexcept>  /* for std::invalid_argument, std::runtime_error */
#include <cerrno>     /* for errno */

using namespace rdf;

static rdf::reader::implementation*
rdf_reader_for(FILE* stream,
               const char* const content_type = nullptr,
               const char* const charset = nullptr,
               const char* const base_uri = nullptr) {
#ifdef HAVE_LIBRAPTOR2
  /* Only the Raptor implementation supports content autodetection at the moment: */
  if (!content_type) {
    return rdf_reader_for_raptor(stream, content_type, charset, base_uri);
  }
#endif

  const format* const format = format::find_for_content_type(content_type);
  if (!format) {
    return nullptr; /* unknown content type */
  }

#ifndef DISABLE_JSONLD
  if (std::strcmp("jsonld", format->module_name) == 0) {
    return rdf_reader_for_jsonld(stream, content_type, charset, base_uri);
  }
#endif

#ifndef DISABLE_NQUADS
  if (std::strcmp("nquads", format->module_name) == 0) {
    return rdf_reader_for_nquads(stream, content_type, charset, base_uri);
  }
#endif

#ifdef HAVE_LIBRAPTOR2
  if (std::strcmp("raptor", format->module_name) == 0) {
    return rdf_reader_for_raptor(stream, content_type, charset, base_uri);
  }
#endif

#ifdef HAVE_LIBSERD
  if (std::strcmp("serd", format->module_name) == 0) {
    return rdf_reader_for_serd(stream, content_type, charset, base_uri);
  }
#endif

#ifndef DISABLE_TRIX
  if (std::strcmp("trix", format->module_name) == 0) {
    return rdf_reader_for_trix(stream, content_type, charset, base_uri);
  }
#endif

  (void)stream, (void)charset, (void)base_uri;
  assert(false && "inconsistent content type definitions");
  return nullptr; /* no implementation available */
}

reader::reader(const std::string& file_path,
               const std::string& content_type,
               const std::string& charset,
               const std::string& base_uri)
  : _implementation(nullptr) {
  FILE *fin = fopen(file_path.c_str(), "r");
  if (fin == nullptr) {
    throw std::invalid_argument("unable to open file " + file_path + " " + strerror(errno));
  }
  _implementation = std::unique_ptr<implementation>(rdf_reader_for(fin, content_type.c_str(),
                                                                   charset.c_str(), base_uri.c_str()));
  if (!_implementation) {
    throw std::invalid_argument("unknown content type: " + content_type);
  }
}

reader::reader(std::istream& stream,
               const std::string& content_type,
               const std::string& charset,
               const std::string& base_uri)
  : _implementation(nullptr) {
  (void)stream, (void)content_type, (void)charset, (void)base_uri; // TODO
}

reader::reader(FILE* const stream)
  : _implementation(rdf_reader_for(stream)) {
  if (!_implementation) {
    throw std::invalid_argument("unable to guess the input content type");
  }
}

reader::reader(FILE* const stream,
               const std::string& content_type,
               const std::string& charset,
               const std::string& base_uri)
  : _implementation(rdf_reader_for(stream, content_type.c_str(), charset.c_str(), base_uri.c_str())) {
  if (!_implementation) {
    throw std::invalid_argument("unknown content type: " + content_type);
  }
}

reader::~reader() noexcept = default;

reader::reader(reader&&) /*noexcept*/ = default;

reader&
reader::operator=(reader&&) /*noexcept*/ = default;

void
reader::read_triples(std::function<void (std::unique_ptr<rdf::triple>)> callback) {
  assert(_implementation != nullptr);
  _implementation->read_triples(callback);
}

void
reader::read_quads(std::function<void (std::unique_ptr<rdf::quad>)> callback) {
  assert(_implementation != nullptr);
  _implementation->read_quads(callback);
}

void
reader::abort() {
  assert(_implementation != nullptr);
  _implementation->abort();
}
<commit_msg>avoid potential `std::bad_alloc` for error string construction<commit_after>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "reader.h"
#include "reader/impl.h"

#ifndef DISABLE_JSONLD
#include "reader/jsonld.h"
#endif

#ifndef DISABLE_NQUADS
#include "reader/nquads.h"
#endif

#ifndef DISABLE_TRIX
#include "reader/trix.h"
#endif

#ifdef HAVE_LIBRAPTOR2
#include "raptor.h"
#include "reader/raptor.h"
#endif

#ifdef HAVE_LIBSERD
#include "reader/serd.h"
#endif

#include "format.h"
#include "quad.h"
#include "term.h"
#include "triple.h"

#include <cassert>    /* for assert() */
#include <cstring>    /* for std::strcmp() */
#include <functional> /* for std::function */
#include <stdexcept>  /* for std::invalid_argument, std::runtime_error */
#include <cerrno>     /* for errno */
#include <cstdio>     /* for std::sprintf() */

using namespace rdf;

static rdf::reader::implementation*
rdf_reader_for(FILE* stream,
               const char* const content_type = nullptr,
               const char* const charset = nullptr,
               const char* const base_uri = nullptr) {
#ifdef HAVE_LIBRAPTOR2
  /* Only the Raptor implementation supports content autodetection at the moment: */
  if (!content_type) {
    return rdf_reader_for_raptor(stream, content_type, charset, base_uri);
  }
#endif

  const format* const format = format::find_for_content_type(content_type);
  if (!format) {
    return nullptr; /* unknown content type */
  }

#ifndef DISABLE_JSONLD
  if (std::strcmp("jsonld", format->module_name) == 0) {
    return rdf_reader_for_jsonld(stream, content_type, charset, base_uri);
  }
#endif

#ifndef DISABLE_NQUADS
  if (std::strcmp("nquads", format->module_name) == 0) {
    return rdf_reader_for_nquads(stream, content_type, charset, base_uri);
  }
#endif

#ifdef HAVE_LIBRAPTOR2
  if (std::strcmp("raptor", format->module_name) == 0) {
    return rdf_reader_for_raptor(stream, content_type, charset, base_uri);
  }
#endif

#ifdef HAVE_LIBSERD
  if (std::strcmp("serd", format->module_name) == 0) {
    return rdf_reader_for_serd(stream, content_type, charset, base_uri);
  }
#endif

#ifndef DISABLE_TRIX
  if (std::strcmp("trix", format->module_name) == 0) {
    return rdf_reader_for_trix(stream, content_type, charset, base_uri);
  }
#endif

  (void)stream, (void)charset, (void)base_uri;
  assert(false && "inconsistent content type definitions");
  return nullptr; /* no implementation available */
}

reader::reader(const std::string& file_path,
               const std::string& content_type,
               const std::string& charset,
               const std::string& base_uri)
  : _implementation(nullptr) {

  FILE *fin = fopen(file_path.c_str(), "r");

  if (fin == nullptr) {
    char buffer[1024];
    std::snprintf(buffer, 1024, "unable to open file %s %s", file_path.c_str(), strerror(errno));
    throw std::invalid_argument(buffer);
  }

  _implementation = std::unique_ptr<implementation>(rdf_reader_for(fin, content_type.c_str(),
                                                                   charset.c_str(), base_uri.c_str()));
  if (!_implementation) {
    throw std::invalid_argument("unknown content type: " + content_type);
  }
}

reader::reader(std::istream& stream,
               const std::string& content_type,
               const std::string& charset,
               const std::string& base_uri)
  : _implementation(nullptr) {
  (void)stream, (void)content_type, (void)charset, (void)base_uri; // TODO
}

reader::reader(FILE* const stream)
  : _implementation(rdf_reader_for(stream)) {
  if (!_implementation) {
    throw std::invalid_argument("unable to guess the input content type");
  }
}

reader::reader(FILE* const stream,
               const std::string& content_type,
               const std::string& charset,
               const std::string& base_uri)
  : _implementation(rdf_reader_for(stream, content_type.c_str(), charset.c_str(), base_uri.c_str())) {
  if (!_implementation) {
    throw std::invalid_argument("unknown content type: " + content_type);
  }
}

reader::~reader() noexcept = default;

reader::reader(reader&&) /*noexcept*/ = default;

reader&
reader::operator=(reader&&) /*noexcept*/ = default;

void
reader::read_triples(std::function<void (std::unique_ptr<rdf::triple>)> callback) {
  assert(_implementation != nullptr);
  _implementation->read_triples(callback);
}

void
reader::read_quads(std::function<void (std::unique_ptr<rdf::quad>)> callback) {
  assert(_implementation != nullptr);
  _implementation->read_quads(callback);
}

void
reader::abort() {
  assert(_implementation != nullptr);
  _implementation->abort();
}
<|endoftext|>


<commit_before>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)

#include <google/protobuf/compiler/subprocess.h>

#include <algorithm>
#include <iostream>

#ifndef _WIN32
#include <errno.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <signal.h>
#endif

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/substitute.h>

namespace google {
namespace protobuf {
namespace compiler {

#ifdef _WIN32

static void CloseHandleOrDie(HANDLE handle) {
  if (!CloseHandle(handle)) {
    GOOGLE_LOG(FATAL) << "CloseHandle: "
                      << Subprocess::Win32ErrorMessage(GetLastError());
  }
}

Subprocess::Subprocess()
    : process_start_error_(ERROR_SUCCESS),
      child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}

Subprocess::~Subprocess() {
  if (child_stdin_ != NULL) {
    CloseHandleOrDie(child_stdin_);
  }
  if (child_stdout_ != NULL) {
    CloseHandleOrDie(child_stdout_);
  }
}

void Subprocess::Start(const string& program, SearchMode search_mode) {
  // Create the pipes.
  HANDLE stdin_pipe_read;
  HANDLE stdin_pipe_write;
  HANDLE stdout_pipe_read;
  HANDLE stdout_pipe_write;

  if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) {
    GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
  }
  if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) {
    GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
  }

  // Make child side of the pipes inheritable.
  if (!SetHandleInformation(stdin_pipe_read,
                            HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
    GOOGLE_LOG(FATAL) << "SetHandleInformation: "
                      << Win32ErrorMessage(GetLastError());
  }
  if (!SetHandleInformation(stdout_pipe_write,
                            HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
    GOOGLE_LOG(FATAL) << "SetHandleInformation: "
                      << Win32ErrorMessage(GetLastError());
  }

  // Setup STARTUPINFO to redirect handles.
  STARTUPINFOA startup_info;
  ZeroMemory(&startup_info, sizeof(startup_info));
  startup_info.cb = sizeof(startup_info);
  startup_info.dwFlags = STARTF_USESTDHANDLES;
  startup_info.hStdInput = stdin_pipe_read;
  startup_info.hStdOutput = stdout_pipe_write;
  startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);

  if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
    GOOGLE_LOG(FATAL) << "GetStdHandle: "
                      << Win32ErrorMessage(GetLastError());
  }

  // CreateProcess() mutates its second parameter.  WTF?
  char* name_copy = strdup(program.c_str());

  // Create the process.
  PROCESS_INFORMATION process_info;

  if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(),
                     (search_mode == SEARCH_PATH) ? name_copy : NULL,
                     NULL,  // process security attributes
                     NULL,  // thread security attributes
                     TRUE,  // inherit handles?
                     0,     // obscure creation flags
                     NULL,  // environment (inherit from parent)
                     NULL,  // current directory (inherit from parent)
                     &startup_info,
                     &process_info)) {
    child_handle_ = process_info.hProcess;
    CloseHandleOrDie(process_info.hThread);
    child_stdin_ = stdin_pipe_write;
    child_stdout_ = stdout_pipe_read;
  } else {
    process_start_error_ = GetLastError();
    CloseHandleOrDie(stdin_pipe_write);
    CloseHandleOrDie(stdout_pipe_read);
  }

  CloseHandleOrDie(stdin_pipe_read);
  CloseHandleOrDie(stdout_pipe_write);
  free(name_copy);
}

bool Subprocess::Communicate(const Message& input, Message* output,
                             string* error) {
  if (process_start_error_ != ERROR_SUCCESS) {
    *error = Win32ErrorMessage(process_start_error_);
    return false;
  }

  GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first.";

  string input_data = input.SerializeAsString();
  string output_data;

  int input_pos = 0;

  while (child_stdout_ != NULL) {
    HANDLE handles[2];
    int handle_count = 0;

    if (child_stdin_ != NULL) {
      handles[handle_count++] = child_stdin_;
    }
    if (child_stdout_ != NULL) {
      handles[handle_count++] = child_stdout_;
    }

    DWORD wait_result =
        WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);

    HANDLE signaled_handle;
    if (wait_result >= WAIT_OBJECT_0 &&
        wait_result < WAIT_OBJECT_0 + handle_count) {
      signaled_handle = handles[wait_result - WAIT_OBJECT_0];
    } else if (wait_result == WAIT_FAILED) {
      GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: "
                        << Win32ErrorMessage(GetLastError());
    } else {
      GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
                        << wait_result;
    }

    if (signaled_handle == child_stdin_) {
      DWORD n;
      if (!WriteFile(child_stdin_,
                     input_data.data() + input_pos,
                     input_data.size() - input_pos,
                     &n, NULL)) {
        // Child closed pipe.  Presumably it will report an error later.
        // Pretend we're done for now.
        input_pos = input_data.size();
      } else {
        input_pos += n;
      }

      if (input_pos == input_data.size()) {
        // We're done writing.  Close.
        CloseHandleOrDie(child_stdin_);
        child_stdin_ = NULL;
      }
    } else if (signaled_handle == child_stdout_) {
      char buffer[4096];
      DWORD n;

      if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) {
        // We're done reading.  Close.
        CloseHandleOrDie(child_stdout_);
        child_stdout_ = NULL;
      } else {
        output_data.append(buffer, n);
      }
    }
  }

  if (child_stdin_ != NULL) {
    // Child did not finish reading input before it closed the output.
    // Presumably it exited with an error.
    CloseHandleOrDie(child_stdin_);
    child_stdin_ = NULL;
  }

  DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);

  if (wait_result == WAIT_FAILED) {
    GOOGLE_LOG(FATAL) << "WaitForSingleObject: "
                      << Win32ErrorMessage(GetLastError());
  } else if (wait_result != WAIT_OBJECT_0) {
    GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: "
                      << wait_result;
  }

  DWORD exit_code;
  if (!GetExitCodeProcess(child_handle_, &exit_code)) {
    GOOGLE_LOG(FATAL) << "GetExitCodeProcess: "
                      << Win32ErrorMessage(GetLastError());
  }

  CloseHandleOrDie(child_handle_);
  child_handle_ = NULL;

  if (exit_code != 0) {
    *error = strings::Substitute(
        "Plugin failed with status code $0.", exit_code);
    return false;
  }

  if (!output->ParseFromString(output_data)) {
    *error = "Plugin output is unparseable: " + CEscape(output_data);
    return false;
  }

  return true;
}

string Subprocess::Win32ErrorMessage(DWORD error_code) {
  char* message;

  // WTF?
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL, error_code, 0,
                (LPTSTR)&message,  // NOT A BUG!
                0, NULL);

  string result = message;
  LocalFree(message);
  return result;
}

// ===================================================================

#else  // _WIN32

Subprocess::Subprocess()
    : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}

Subprocess::~Subprocess() {
  if (child_stdin_ != -1) {
    close(child_stdin_);
  }
  if (child_stdout_ != -1) {
    close(child_stdout_);
  }
}

void Subprocess::Start(const string& program, SearchMode search_mode) {
  // Note that we assume that there are no other threads, thus we don't have to
  // do crazy stuff like using socket pairs or avoiding libc locks.

  // [0] is read end, [1] is write end.
  int stdin_pipe[2];
  int stdout_pipe[2];

  GOOGLE_CHECK(pipe(stdin_pipe) != -1);
  GOOGLE_CHECK(pipe(stdout_pipe) != -1);

  char* argv[2] = { strdup(program.c_str()), NULL };

  child_pid_ = fork();
  if (child_pid_ == -1) {
    GOOGLE_LOG(FATAL) << "fork: " << strerror(errno);
  } else if (child_pid_ == 0) {
    // We are the child.
    dup2(stdin_pipe[0], STDIN_FILENO);
    dup2(stdout_pipe[1], STDOUT_FILENO);

    close(stdin_pipe[0]);
    close(stdin_pipe[1]);
    close(stdout_pipe[0]);
    close(stdout_pipe[1]);

    switch (search_mode) {
      case SEARCH_PATH:
        execvp(argv[0], argv);
        break;
      case EXACT_NAME:
        execv(argv[0], argv);
        break;
    }

    // Write directly to STDERR_FILENO to avoid stdio code paths that may do
    // stuff that is unsafe here.
    int ignored;
    ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
    const char* message = ": program not found or is not executable\n";
    ignored = write(STDERR_FILENO, message, strlen(message));
    (void) ignored;

    // Must use _exit() rather than exit() to avoid flushing output buffers
    // that will also be flushed by the parent.
    _exit(1);
  } else {
    free(argv[0]);

    close(stdin_pipe[0]);
    close(stdout_pipe[1]);

    child_stdin_ = stdin_pipe[1];
    child_stdout_ = stdout_pipe[0];
  }
}

bool Subprocess::Communicate(const Message& input, Message* output,
                             string* error) {

  GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first.";

  // The "sighandler_t" typedef is GNU-specific, so define our own.
  typedef void SignalHandler(int);

  // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
  SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);

  string input_data = input.SerializeAsString();
  string output_data;

  int input_pos = 0;
  int max_fd = max(child_stdin_, child_stdout_);

  while (child_stdout_ != -1) {
    fd_set read_fds;
    fd_set write_fds;
    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);
    if (child_stdout_ != -1) {
      FD_SET(child_stdout_, &read_fds);
    }
    if (child_stdin_ != -1) {
      FD_SET(child_stdin_, &write_fds);
    }

    if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
      if (errno == EINTR) {
        // Interrupted by signal.  Try again.
        continue;
      } else {
        GOOGLE_LOG(FATAL) << "select: " << strerror(errno);
      }
    }

    if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) {
      int n = write(child_stdin_, input_data.data() + input_pos,
                                  input_data.size() - input_pos);
      if (n < 0) {
        // Child closed pipe.  Presumably it will report an error later.
        // Pretend we're done for now.
        input_pos = input_data.size();
      } else {
        input_pos += n;
      }

      if (input_pos == input_data.size()) {
        // We're done writing.  Close.
        close(child_stdin_);
        child_stdin_ = -1;
      }
    }

    if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
      char buffer[4096];
      int n = read(child_stdout_, buffer, sizeof(buffer));

      if (n > 0) {
        output_data.append(buffer, n);
      } else {
        // We're done reading.  Close.
        close(child_stdout_);
        child_stdout_ = -1;
      }
    }
  }

  if (child_stdin_ != -1) {
    // Child did not finish reading input before it closed the output.
    // Presumably it exited with an error.
    close(child_stdin_);
    child_stdin_ = -1;
  }

  int status;
  while (waitpid(child_pid_, &status, 0) == -1) {
    if (errno != EINTR) {
      GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno);
    }
  }

  // Restore SIGPIPE handling.
  signal(SIGPIPE, old_pipe_handler);

  if (WIFEXITED(status)) {
    if (WEXITSTATUS(status) != 0) {
      int error_code = WEXITSTATUS(status);
      *error = strings::Substitute(
          "Plugin failed with status code $0.", error_code);
      return false;
    }
  } else if (WIFSIGNALED(status)) {
    int signal = WTERMSIG(status);
    *error = strings::Substitute(
        "Plugin killed by signal $0.", signal);
    return false;
  } else {
    *error = "Neither WEXITSTATUS nor WTERMSIG is true?";
    return false;
  }

  if (!output->ParseFromString(output_data)) {
    *error = "Plugin output is unparseable: " + CEscape(output_data);
    return false;
  }

  return true;
}

#endif  // !_WIN32

}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<commit_msg>Fix "sometimes-uninitialized" warning on Windows Clang.<commit_after>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

// Author: kenton@google.com (Kenton Varda)

#include <google/protobuf/compiler/subprocess.h>

#include <algorithm>
#include <iostream>

#ifndef _WIN32
#include <errno.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <signal.h>
#endif

#include <google/protobuf/stubs/common.h>
#include <google/protobuf/message.h>
#include <google/protobuf/stubs/substitute.h>

namespace google {
namespace protobuf {
namespace compiler {

#ifdef _WIN32

static void CloseHandleOrDie(HANDLE handle) {
  if (!CloseHandle(handle)) {
    GOOGLE_LOG(FATAL) << "CloseHandle: "
                      << Subprocess::Win32ErrorMessage(GetLastError());
  }
}

Subprocess::Subprocess()
    : process_start_error_(ERROR_SUCCESS),
      child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {}

Subprocess::~Subprocess() {
  if (child_stdin_ != NULL) {
    CloseHandleOrDie(child_stdin_);
  }
  if (child_stdout_ != NULL) {
    CloseHandleOrDie(child_stdout_);
  }
}

void Subprocess::Start(const string& program, SearchMode search_mode) {
  // Create the pipes.
  HANDLE stdin_pipe_read;
  HANDLE stdin_pipe_write;
  HANDLE stdout_pipe_read;
  HANDLE stdout_pipe_write;

  if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) {
    GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
  }
  if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) {
    GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError());
  }

  // Make child side of the pipes inheritable.
  if (!SetHandleInformation(stdin_pipe_read,
                            HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
    GOOGLE_LOG(FATAL) << "SetHandleInformation: "
                      << Win32ErrorMessage(GetLastError());
  }
  if (!SetHandleInformation(stdout_pipe_write,
                            HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) {
    GOOGLE_LOG(FATAL) << "SetHandleInformation: "
                      << Win32ErrorMessage(GetLastError());
  }

  // Setup STARTUPINFO to redirect handles.
  STARTUPINFOA startup_info;
  ZeroMemory(&startup_info, sizeof(startup_info));
  startup_info.cb = sizeof(startup_info);
  startup_info.dwFlags = STARTF_USESTDHANDLES;
  startup_info.hStdInput = stdin_pipe_read;
  startup_info.hStdOutput = stdout_pipe_write;
  startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);

  if (startup_info.hStdError == INVALID_HANDLE_VALUE) {
    GOOGLE_LOG(FATAL) << "GetStdHandle: "
                      << Win32ErrorMessage(GetLastError());
  }

  // CreateProcess() mutates its second parameter.  WTF?
  char* name_copy = strdup(program.c_str());

  // Create the process.
  PROCESS_INFORMATION process_info;

  if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(),
                     (search_mode == SEARCH_PATH) ? name_copy : NULL,
                     NULL,  // process security attributes
                     NULL,  // thread security attributes
                     TRUE,  // inherit handles?
                     0,     // obscure creation flags
                     NULL,  // environment (inherit from parent)
                     NULL,  // current directory (inherit from parent)
                     &startup_info,
                     &process_info)) {
    child_handle_ = process_info.hProcess;
    CloseHandleOrDie(process_info.hThread);
    child_stdin_ = stdin_pipe_write;
    child_stdout_ = stdout_pipe_read;
  } else {
    process_start_error_ = GetLastError();
    CloseHandleOrDie(stdin_pipe_write);
    CloseHandleOrDie(stdout_pipe_read);
  }

  CloseHandleOrDie(stdin_pipe_read);
  CloseHandleOrDie(stdout_pipe_write);
  free(name_copy);
}

bool Subprocess::Communicate(const Message& input, Message* output,
                             string* error) {
  if (process_start_error_ != ERROR_SUCCESS) {
    *error = Win32ErrorMessage(process_start_error_);
    return false;
  }

  GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first.";

  string input_data = input.SerializeAsString();
  string output_data;

  int input_pos = 0;

  while (child_stdout_ != NULL) {
    HANDLE handles[2];
    int handle_count = 0;

    if (child_stdin_ != NULL) {
      handles[handle_count++] = child_stdin_;
    }
    if (child_stdout_ != NULL) {
      handles[handle_count++] = child_stdout_;
    }

    DWORD wait_result =
        WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE);

    HANDLE signaled_handle = NULL;
    if (wait_result >= WAIT_OBJECT_0 &&
        wait_result < WAIT_OBJECT_0 + handle_count) {
      signaled_handle = handles[wait_result - WAIT_OBJECT_0];
    } else if (wait_result == WAIT_FAILED) {
      GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: "
                        << Win32ErrorMessage(GetLastError());
    } else {
      GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: "
                        << wait_result;
    }

    if (signaled_handle == child_stdin_) {
      DWORD n;
      if (!WriteFile(child_stdin_,
                     input_data.data() + input_pos,
                     input_data.size() - input_pos,
                     &n, NULL)) {
        // Child closed pipe.  Presumably it will report an error later.
        // Pretend we're done for now.
        input_pos = input_data.size();
      } else {
        input_pos += n;
      }

      if (input_pos == input_data.size()) {
        // We're done writing.  Close.
        CloseHandleOrDie(child_stdin_);
        child_stdin_ = NULL;
      }
    } else if (signaled_handle == child_stdout_) {
      char buffer[4096];
      DWORD n;

      if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) {
        // We're done reading.  Close.
        CloseHandleOrDie(child_stdout_);
        child_stdout_ = NULL;
      } else {
        output_data.append(buffer, n);
      }
    }
  }

  if (child_stdin_ != NULL) {
    // Child did not finish reading input before it closed the output.
    // Presumably it exited with an error.
    CloseHandleOrDie(child_stdin_);
    child_stdin_ = NULL;
  }

  DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE);

  if (wait_result == WAIT_FAILED) {
    GOOGLE_LOG(FATAL) << "WaitForSingleObject: "
                      << Win32ErrorMessage(GetLastError());
  } else if (wait_result != WAIT_OBJECT_0) {
    GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: "
                      << wait_result;
  }

  DWORD exit_code;
  if (!GetExitCodeProcess(child_handle_, &exit_code)) {
    GOOGLE_LOG(FATAL) << "GetExitCodeProcess: "
                      << Win32ErrorMessage(GetLastError());
  }

  CloseHandleOrDie(child_handle_);
  child_handle_ = NULL;

  if (exit_code != 0) {
    *error = strings::Substitute(
        "Plugin failed with status code $0.", exit_code);
    return false;
  }

  if (!output->ParseFromString(output_data)) {
    *error = "Plugin output is unparseable: " + CEscape(output_data);
    return false;
  }

  return true;
}

string Subprocess::Win32ErrorMessage(DWORD error_code) {
  char* message;

  // WTF?
  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL, error_code, 0,
                (LPTSTR)&message,  // NOT A BUG!
                0, NULL);

  string result = message;
  LocalFree(message);
  return result;
}

// ===================================================================

#else  // _WIN32

Subprocess::Subprocess()
    : child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {}

Subprocess::~Subprocess() {
  if (child_stdin_ != -1) {
    close(child_stdin_);
  }
  if (child_stdout_ != -1) {
    close(child_stdout_);
  }
}

void Subprocess::Start(const string& program, SearchMode search_mode) {
  // Note that we assume that there are no other threads, thus we don't have to
  // do crazy stuff like using socket pairs or avoiding libc locks.

  // [0] is read end, [1] is write end.
  int stdin_pipe[2];
  int stdout_pipe[2];

  GOOGLE_CHECK(pipe(stdin_pipe) != -1);
  GOOGLE_CHECK(pipe(stdout_pipe) != -1);

  char* argv[2] = { strdup(program.c_str()), NULL };

  child_pid_ = fork();
  if (child_pid_ == -1) {
    GOOGLE_LOG(FATAL) << "fork: " << strerror(errno);
  } else if (child_pid_ == 0) {
    // We are the child.
    dup2(stdin_pipe[0], STDIN_FILENO);
    dup2(stdout_pipe[1], STDOUT_FILENO);

    close(stdin_pipe[0]);
    close(stdin_pipe[1]);
    close(stdout_pipe[0]);
    close(stdout_pipe[1]);

    switch (search_mode) {
      case SEARCH_PATH:
        execvp(argv[0], argv);
        break;
      case EXACT_NAME:
        execv(argv[0], argv);
        break;
    }

    // Write directly to STDERR_FILENO to avoid stdio code paths that may do
    // stuff that is unsafe here.
    int ignored;
    ignored = write(STDERR_FILENO, argv[0], strlen(argv[0]));
    const char* message = ": program not found or is not executable\n";
    ignored = write(STDERR_FILENO, message, strlen(message));
    (void) ignored;

    // Must use _exit() rather than exit() to avoid flushing output buffers
    // that will also be flushed by the parent.
    _exit(1);
  } else {
    free(argv[0]);

    close(stdin_pipe[0]);
    close(stdout_pipe[1]);

    child_stdin_ = stdin_pipe[1];
    child_stdout_ = stdout_pipe[0];
  }
}

bool Subprocess::Communicate(const Message& input, Message* output,
                             string* error) {

  GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first.";

  // The "sighandler_t" typedef is GNU-specific, so define our own.
  typedef void SignalHandler(int);

  // Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
  SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN);

  string input_data = input.SerializeAsString();
  string output_data;

  int input_pos = 0;
  int max_fd = max(child_stdin_, child_stdout_);

  while (child_stdout_ != -1) {
    fd_set read_fds;
    fd_set write_fds;
    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);
    if (child_stdout_ != -1) {
      FD_SET(child_stdout_, &read_fds);
    }
    if (child_stdin_ != -1) {
      FD_SET(child_stdin_, &write_fds);
    }

    if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) {
      if (errno == EINTR) {
        // Interrupted by signal.  Try again.
        continue;
      } else {
        GOOGLE_LOG(FATAL) << "select: " << strerror(errno);
      }
    }

    if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) {
      int n = write(child_stdin_, input_data.data() + input_pos,
                                  input_data.size() - input_pos);
      if (n < 0) {
        // Child closed pipe.  Presumably it will report an error later.
        // Pretend we're done for now.
        input_pos = input_data.size();
      } else {
        input_pos += n;
      }

      if (input_pos == input_data.size()) {
        // We're done writing.  Close.
        close(child_stdin_);
        child_stdin_ = -1;
      }
    }

    if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) {
      char buffer[4096];
      int n = read(child_stdout_, buffer, sizeof(buffer));

      if (n > 0) {
        output_data.append(buffer, n);
      } else {
        // We're done reading.  Close.
        close(child_stdout_);
        child_stdout_ = -1;
      }
    }
  }

  if (child_stdin_ != -1) {
    // Child did not finish reading input before it closed the output.
    // Presumably it exited with an error.
    close(child_stdin_);
    child_stdin_ = -1;
  }

  int status;
  while (waitpid(child_pid_, &status, 0) == -1) {
    if (errno != EINTR) {
      GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno);
    }
  }

  // Restore SIGPIPE handling.
  signal(SIGPIPE, old_pipe_handler);

  if (WIFEXITED(status)) {
    if (WEXITSTATUS(status) != 0) {
      int error_code = WEXITSTATUS(status);
      *error = strings::Substitute(
          "Plugin failed with status code $0.", error_code);
      return false;
    }
  } else if (WIFSIGNALED(status)) {
    int signal = WTERMSIG(status);
    *error = strings::Substitute(
        "Plugin killed by signal $0.", signal);
    return false;
  } else {
    *error = "Neither WEXITSTATUS nor WTERMSIG is true?";
    return false;
  }

  if (!output->ParseFromString(output_data)) {
    *error = "Plugin output is unparseable: " + CEscape(output_data);
    return false;
  }

  return true;
}

#endif  // !_WIN32

}  // namespace compiler
}  // namespace protobuf
}  // namespace google
<|endoftext|>


<commit_before>/*
 * gst_qe_module.cpp
 *
 *  Created on: Jul 2, 2015
 *      Author: mkolny
 */

#include "gst_qe_module.h"
#include "sigc++lambdahack.h"
#include "gvalue-converter/gvalue_base.h"
#include "gvalue-converter/gvalue_enum.h"
#include "protocol/deserializer.h"
#include "controller/controller.h"
#include "controller/element_path_processor.h"

template<typename T>
static void free_data(T *data) { delete data; }

GstQEModule::GstQEModule(bool type_module, bool pad_path_module,
		GstreamerInfo_InfoType info_type,
		const std::string& qe_name, GType qe_gtype, const Glib::RefPtr<Gtk::Builder>& builder)
:  qe_gtype(qe_gtype),
   info_type(info_type),
  type_module(type_module)
{
	builder->get_widget("existing" + qe_name + "HooksTreeView", existing_hooks_tree_view);
	qe_hooks_model = Gtk::ListStore::create(qe_hooks_model_columns);
	existing_hooks_tree_view->set_model(qe_hooks_model);

	if (pad_path_module)
	{
		builder->get_widget("any" + qe_name + "PathCheckButton", any_path_check_button);
		existing_hooks_tree_view->append_column("Pad path", qe_hooks_model_columns.pad_path);
	}

	if (type_module)
	{
		builder->get_widget("any" + qe_name + "CheckButton", any_qe_check_button);
		any_qe_check_button->signal_toggled().connect([this] { qe_types_combobox->set_sensitive(!any_qe_check_button->get_active()); });

		builder->get_widget("types" + qe_name + "ComboBox", qe_types_combobox);
		qe_types_model = Gtk::ListStore::create(qe_types_model_columns);
		qe_types_combobox->set_model(qe_types_model);
		qe_types_combobox->pack_start(qe_types_model_columns.type_name);

		existing_hooks_tree_view->append_column(qe_name + " type", qe_hooks_model_columns.qe_type);
	}

	builder->get_widget(qe_name + "ListTreeView", qe_list_tree_view);
	qe_list_tree_view->signal_row_activated().connect(sigc::mem_fun(*this, &GstQEModule::qeListTreeView_row_activated_cb));
	qe_list_model = Gtk::ListStore::create(qe_list_model_columns);
	qe_list_tree_view->set_model(qe_list_model);
	qe_list_tree_view->append_column("", qe_list_model_columns.type);

	builder->get_widget("details" + qe_name + "TreeView", qe_details_tree_view);
	qe_details_model = Gtk::TreeStore::create(qe_details_model_columns);
	qe_details_tree_view->set_model(qe_details_model);
	qe_details_tree_view->append_column("Name", qe_details_model_columns.name);
	qe_details_tree_view->append_column("Value", qe_details_model_columns.value);

	builder->get_widget("startWatching" + qe_name + "Button", start_watching_qe_button);
	start_watching_qe_button->signal_clicked().connect(sigc::mem_fun(*this, &GstQEModule::startWatchingQEButton_click_cb));

	create_dispatcher("qebm", sigc::mem_fun(*this, &GstQEModule::qebm_received_), (GDestroyNotify)free_data<GstreamerQEBM>);
	create_dispatcher("confirmation", sigc::mem_fun(*this, &GstQEModule::confirmation_received_),
			info_type == GstreamerInfo_InfoType_MESSAGE ? (GDestroyNotify)free_data<MessageWatch> : (GDestroyNotify)free_data<PadWatch>);
	create_dispatcher("enum", sigc::mem_fun(*this, &GstQEModule::enum_list_changed_), (GDestroyNotify)free_data<std::string>);

}

void GstQEModule::set_controller(const std::shared_ptr<Controller> &controller)
{
	IBaseView::set_controller(controller);
	controller->on_qebm_received.connect(sigc::mem_fun(*this, &GstQEModule::qebm_received));

	controller->on_enum_list_changed.connect(sigc::mem_fun(*this, &GstQEModule::enum_list_changed));

	if (info_type != GstreamerInfo_InfoType_MESSAGE)
	{
		controller->on_pad_watch_confirmation_received.connect(sigc::mem_fun(*this, &GstQEModule::pad_confirmation_received));
	}
}

void GstQEModule::enum_list_changed(const Glib::ustring &enum_name)
{
	if ((qe_gtype == gst_query_type_get_type() && enum_name == "GstQueryType") ||
			(qe_gtype == gst_event_type_get_type() && enum_name == "GstEventType"))
	{
		gui_push("enum", new std::string(enum_name));
		gui_emit("enum");
	}
}

void GstQEModule::enum_list_changed_()
{
	qe_types_model->clear();
	std::string* type_name = gui_pop<std::string*>("enum");
	GstEnumType type = const_cast<GstEnumContainer&>(controller->get_enum_container()).get_type(*type_name);
	for (auto val : type.get_values())
	{
		Gtk::TreeModel::Row row = *(qe_types_model->append());
		row[qe_types_model_columns.type_id] = val.first;
		row[qe_types_model_columns.type_name] = val.second.nick;
	}
	if (qe_types_model->children().size() > 0)
	{
		qe_types_combobox->set_active(0);
	}
	delete type_name;
}

PadWatch_WatchType GstQEModule::get_watch_type() const
{
	switch (info_type)
	{
	case GstreamerInfo_InfoType_BUFFER:
		return PadWatch_WatchType_BUFFER;
	case GstreamerInfo_InfoType_EVENT:
		return PadWatch_WatchType_EVENT;
	case GstreamerInfo_InfoType_QUERY:
		return PadWatch_WatchType_QUERY;
	default:
		return (PadWatch_WatchType)-1;
	}
}

void GstQEModule::update_hook_list(PadWatch *conf)
{
	if (conf->watch_type() != get_watch_type())
		return;

	if (conf->toggle() == ENABLE)
	{
		Gtk::TreeModel::Row row = *(qe_hooks_model->append());
		row[qe_hooks_model_columns.pad_path] = conf->pad_path();
		row[qe_hooks_model_columns.qe_type] = conf->qe_type();
	}
	else
	{
		for (auto iter = qe_hooks_model->children().begin();
				iter != qe_hooks_model->children().end(); ++iter)
		{
			if ((*iter)[qe_hooks_model_columns.pad_path] == conf->pad_path() &&
					(*iter)[qe_hooks_model_columns.qe_type] == conf->qe_type())
			{
				qe_hooks_model->erase(iter);
				break;
			}
		}
	}
}

void GstQEModule::send_start_stop_command(bool enable)
{
	int qe_type = -1;

	if (type_module && !any_qe_check_button->get_active())
	{
		Gtk::TreeModel::iterator iter = qe_types_combobox->get_active();
		if (!iter)
			return;

		Gtk::TreeModel::Row row = *iter;
		if (!row)
			return;
		qe_type = row[qe_types_model_columns.type_id];
	}

	auto selected_pad = std::dynamic_pointer_cast<PadModel>(controller->get_selected_object());

	if (!selected_pad && !any_path_check_button->get_active())
	{
		return;
	}

	std::string pad_path = any_path_check_button->get_active() ? std::string() : ElementPathProcessor::get_object_path(selected_pad);

	controller->send_pad_watch_command(enable, get_watch_type(), pad_path, qe_type);
}

void GstQEModule::qeListTreeView_row_activated_cb(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column)
{
	Gtk::TreeModel::iterator iter = qe_list_model->get_iter(path);
	if (!iter)
	{
		return;
	}

	Gtk::TreeModel::Row row = *iter;
	Glib::RefPtr<Gst::MiniObject> qe = Glib::wrap(row[qe_list_model_columns.qe], true);
	display_qe_details(qe);
}

void GstQEModule::display_qe_details(const Glib::RefPtr<Gst::MiniObject>& qe)
{
	qe_details_model->clear();
}

void GstQEModule::append_details_row(const std::string &name, const std::string &value)
{
	Gtk::TreeModel::Row row = *(qe_details_model->append());
	row[qe_details_model_columns.name] = name;
	row[qe_details_model_columns.value] = value;
}

void GstQEModule::append_details_from_structure(Gst::Structure& structure)
{
	if (!structure.gobj())
		return;

	structure.foreach([structure, this](const Glib::ustring &name, const Glib::ValueBase &value) -> bool {
		GValue* tmp_val = new GValue;
		*tmp_val = G_VALUE_INIT;
		g_value_init(tmp_val, value.gobj()->g_type);
		g_value_copy(value.gobj(), tmp_val);
		auto gvalue = GValueBase::build_gvalue(tmp_val);
		if (gvalue == nullptr)
			append_details_row(name, std::string("<unsupported type ") + g_type_name(G_VALUE_TYPE(value.gobj())) + ">");
		else
		{
			append_details_row(name, gvalue->to_string());
			delete gvalue;
		}
		return true;
	});
}

void GstQEModule::qebm_received(const GstreamerQEBM &qebm, GstreamerInfo_InfoType type)
{
	if (type == info_type)
	{
		gui_push("qebm", new GstreamerQEBM(qebm));
		gui_emit("qebm");
	}
}

void GstQEModule::qebm_received_()
{
	auto qebm = gui_pop<GstreamerQEBM*>("qebm");
	append_qe_entry(qebm);
	delete qebm;
}

void GstQEModule::pad_confirmation_received(const PadWatch& watch, PadWatch_WatchType type)
{
	if (type == get_watch_type())
	{
		gui_push("confirmation", new PadWatch(watch));
		gui_emit("confirmation");
	}
}

void GstQEModule::confirmation_received_()
{
	auto confirmation = gui_pop<PadWatch*>("confirmation");
	update_hook_list(confirmation);
	delete confirmation;
}

void GstQEModule::startWatchingQEButton_click_cb()
{
	send_start_stop_command(true);
}

void GstQEModule::stopWatchingQEButton_click_cb()
{
	send_start_stop_command(false);
}

<commit_msg>gst-debugger: fill message type combobox on connect<commit_after>/*
 * gst_qe_module.cpp
 *
 *  Created on: Jul 2, 2015
 *      Author: mkolny
 */

#include "gst_qe_module.h"
#include "sigc++lambdahack.h"
#include "gvalue-converter/gvalue_base.h"
#include "gvalue-converter/gvalue_enum.h"
#include "protocol/deserializer.h"
#include "controller/controller.h"
#include "controller/element_path_processor.h"

template<typename T>
static void free_data(T *data) { delete data; }

GstQEModule::GstQEModule(bool type_module, bool pad_path_module,
		GstreamerInfo_InfoType info_type,
		const std::string& qe_name, GType qe_gtype, const Glib::RefPtr<Gtk::Builder>& builder)
:  qe_gtype(qe_gtype),
   info_type(info_type),
  type_module(type_module)
{
	builder->get_widget("existing" + qe_name + "HooksTreeView", existing_hooks_tree_view);
	qe_hooks_model = Gtk::ListStore::create(qe_hooks_model_columns);
	existing_hooks_tree_view->set_model(qe_hooks_model);

	if (pad_path_module)
	{
		builder->get_widget("any" + qe_name + "PathCheckButton", any_path_check_button);
		existing_hooks_tree_view->append_column("Pad path", qe_hooks_model_columns.pad_path);
	}

	if (type_module)
	{
		builder->get_widget("any" + qe_name + "CheckButton", any_qe_check_button);
		any_qe_check_button->signal_toggled().connect([this] { qe_types_combobox->set_sensitive(!any_qe_check_button->get_active()); });

		builder->get_widget("types" + qe_name + "ComboBox", qe_types_combobox);
		qe_types_model = Gtk::ListStore::create(qe_types_model_columns);
		qe_types_combobox->set_model(qe_types_model);
		qe_types_combobox->pack_start(qe_types_model_columns.type_name);

		existing_hooks_tree_view->append_column(qe_name + " type", qe_hooks_model_columns.qe_type);
	}

	builder->get_widget(qe_name + "ListTreeView", qe_list_tree_view);
	qe_list_tree_view->signal_row_activated().connect(sigc::mem_fun(*this, &GstQEModule::qeListTreeView_row_activated_cb));
	qe_list_model = Gtk::ListStore::create(qe_list_model_columns);
	qe_list_tree_view->set_model(qe_list_model);
	qe_list_tree_view->append_column("", qe_list_model_columns.type);

	builder->get_widget("details" + qe_name + "TreeView", qe_details_tree_view);
	qe_details_model = Gtk::TreeStore::create(qe_details_model_columns);
	qe_details_tree_view->set_model(qe_details_model);
	qe_details_tree_view->append_column("Name", qe_details_model_columns.name);
	qe_details_tree_view->append_column("Value", qe_details_model_columns.value);

	builder->get_widget("startWatching" + qe_name + "Button", start_watching_qe_button);
	start_watching_qe_button->signal_clicked().connect(sigc::mem_fun(*this, &GstQEModule::startWatchingQEButton_click_cb));

	create_dispatcher("qebm", sigc::mem_fun(*this, &GstQEModule::qebm_received_), (GDestroyNotify)free_data<GstreamerQEBM>);
	create_dispatcher("confirmation", sigc::mem_fun(*this, &GstQEModule::confirmation_received_),
			info_type == GstreamerInfo_InfoType_MESSAGE ? (GDestroyNotify)free_data<MessageWatch> : (GDestroyNotify)free_data<PadWatch>);
	create_dispatcher("enum", sigc::mem_fun(*this, &GstQEModule::enum_list_changed_), (GDestroyNotify)free_data<std::string>);

}

void GstQEModule::set_controller(const std::shared_ptr<Controller> &controller)
{
	IBaseView::set_controller(controller);
	controller->on_qebm_received.connect(sigc::mem_fun(*this, &GstQEModule::qebm_received));

	controller->on_enum_list_changed.connect(sigc::mem_fun(*this, &GstQEModule::enum_list_changed));

	if (info_type != GstreamerInfo_InfoType_MESSAGE)
	{
		controller->on_pad_watch_confirmation_received.connect(sigc::mem_fun(*this, &GstQEModule::pad_confirmation_received));
	}
}

void GstQEModule::enum_list_changed(const Glib::ustring &enum_name)
{
	if ((qe_gtype == gst_query_type_get_type() && enum_name == "GstQueryType") ||
			(qe_gtype == gst_event_type_get_type() && enum_name == "GstEventType") ||
			(qe_gtype == gst_message_type_get_type() && enum_name == "GstMessageType"))
	{
		gui_push("enum", new std::string(enum_name));
		gui_emit("enum");
	}
}

void GstQEModule::enum_list_changed_()
{
	qe_types_model->clear();
	std::string* type_name = gui_pop<std::string*>("enum");
	GstEnumType type = const_cast<GstEnumContainer&>(controller->get_enum_container()).get_type(*type_name);
	for (auto val : type.get_values())
	{
		Gtk::TreeModel::Row row = *(qe_types_model->append());
		row[qe_types_model_columns.type_id] = val.first;
		row[qe_types_model_columns.type_name] = val.second.nick;
	}
	if (qe_types_model->children().size() > 0)
	{
		qe_types_combobox->set_active(0);
	}
	delete type_name;
}

PadWatch_WatchType GstQEModule::get_watch_type() const
{
	switch (info_type)
	{
	case GstreamerInfo_InfoType_BUFFER:
		return PadWatch_WatchType_BUFFER;
	case GstreamerInfo_InfoType_EVENT:
		return PadWatch_WatchType_EVENT;
	case GstreamerInfo_InfoType_QUERY:
		return PadWatch_WatchType_QUERY;
	default:
		return (PadWatch_WatchType)-1;
	}
}

void GstQEModule::update_hook_list(PadWatch *conf)
{
	if (conf->watch_type() != get_watch_type())
		return;

	if (conf->toggle() == ENABLE)
	{
		Gtk::TreeModel::Row row = *(qe_hooks_model->append());
		row[qe_hooks_model_columns.pad_path] = conf->pad_path();
		row[qe_hooks_model_columns.qe_type] = conf->qe_type();
	}
	else
	{
		for (auto iter = qe_hooks_model->children().begin();
				iter != qe_hooks_model->children().end(); ++iter)
		{
			if ((*iter)[qe_hooks_model_columns.pad_path] == conf->pad_path() &&
					(*iter)[qe_hooks_model_columns.qe_type] == conf->qe_type())
			{
				qe_hooks_model->erase(iter);
				break;
			}
		}
	}
}

void GstQEModule::send_start_stop_command(bool enable)
{
	int qe_type = -1;

	if (type_module && !any_qe_check_button->get_active())
	{
		Gtk::TreeModel::iterator iter = qe_types_combobox->get_active();
		if (!iter)
			return;

		Gtk::TreeModel::Row row = *iter;
		if (!row)
			return;
		qe_type = row[qe_types_model_columns.type_id];
	}

	auto selected_pad = std::dynamic_pointer_cast<PadModel>(controller->get_selected_object());

	if (!selected_pad && !any_path_check_button->get_active())
	{
		return;
	}

	std::string pad_path = any_path_check_button->get_active() ? std::string() : ElementPathProcessor::get_object_path(selected_pad);

	controller->send_pad_watch_command(enable, get_watch_type(), pad_path, qe_type);
}

void GstQEModule::qeListTreeView_row_activated_cb(const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column)
{
	Gtk::TreeModel::iterator iter = qe_list_model->get_iter(path);
	if (!iter)
	{
		return;
	}

	Gtk::TreeModel::Row row = *iter;
	Glib::RefPtr<Gst::MiniObject> qe = Glib::wrap(row[qe_list_model_columns.qe], true);
	display_qe_details(qe);
}

void GstQEModule::display_qe_details(const Glib::RefPtr<Gst::MiniObject>& qe)
{
	qe_details_model->clear();
}

void GstQEModule::append_details_row(const std::string &name, const std::string &value)
{
	Gtk::TreeModel::Row row = *(qe_details_model->append());
	row[qe_details_model_columns.name] = name;
	row[qe_details_model_columns.value] = value;
}

void GstQEModule::append_details_from_structure(Gst::Structure& structure)
{
	if (!structure.gobj())
		return;

	structure.foreach([structure, this](const Glib::ustring &name, const Glib::ValueBase &value) -> bool {
		GValue* tmp_val = new GValue;
		*tmp_val = G_VALUE_INIT;
		g_value_init(tmp_val, value.gobj()->g_type);
		g_value_copy(value.gobj(), tmp_val);
		auto gvalue = GValueBase::build_gvalue(tmp_val);
		if (gvalue == nullptr)
			append_details_row(name, std::string("<unsupported type ") + g_type_name(G_VALUE_TYPE(value.gobj())) + ">");
		else
		{
			append_details_row(name, gvalue->to_string());
			delete gvalue;
		}
		return true;
	});
}

void GstQEModule::qebm_received(const GstreamerQEBM &qebm, GstreamerInfo_InfoType type)
{
	if (type == info_type)
	{
		gui_push("qebm", new GstreamerQEBM(qebm));
		gui_emit("qebm");
	}
}

void GstQEModule::qebm_received_()
{
	auto qebm = gui_pop<GstreamerQEBM*>("qebm");
	append_qe_entry(qebm);
	delete qebm;
}

void GstQEModule::pad_confirmation_received(const PadWatch& watch, PadWatch_WatchType type)
{
	if (type == get_watch_type())
	{
		gui_push("confirmation", new PadWatch(watch));
		gui_emit("confirmation");
	}
}

void GstQEModule::confirmation_received_()
{
	auto confirmation = gui_pop<PadWatch*>("confirmation");
	update_hook_list(confirmation);
	delete confirmation;
}

void GstQEModule::startWatchingQEButton_click_cb()
{
	send_start_stop_command(true);
}

void GstQEModule::stopWatchingQEButton_click_cb()
{
	send_start_stop_command(false);
}

<|endoftext|>


<commit_before>#include "router.h"
#include "service.h"
#include "lambda_service.h"
#include <string>
#include <iostream>
#include <algorithm>

namespace REST {
  workers_services_vector Router::workers_services;
  Router* Router::pInstance = NULL;
  lambda_patterns* Router::patterns = new lambda_patterns();
  int Router::WORKERS = 256;
  std::shared_ptr<Router::Node> Router::root = std::make_shared<Router::Node>();

  Router::Router() {
    workers_services.resize(WORKERS);

    for (int i = 0; i < WORKERS; i++)
      workers_services[i] = std::make_shared<names_services_map>();
  }

  Router* Router::Instance() {
    if(pInstance == NULL){
      pInstance = new Router();
    }
    return pInstance;
  }

  std::shared_ptr<Service> Router::getResource(std::shared_ptr<Request> request, int worker_id) {
    std::shared_ptr<Node> node = match(request->path, request->parameters);

    if (node == nullptr)
      return NULL;

    return node->find_service(worker_id);
  }

  void Router::path(std::string const& path, service_lambda lambda) {
    std::shared_ptr<Router::Node> node = Router::Node::from_path(path);
    node->end()->add_service(std::make_shared<LambdaService>(lambda));
    root->merge(node);
  }

  Router::Node::Node(std::string p, std::shared_ptr<Node> const& pr) : path(p), parent(pr) {
  }

  Router::Node::~Node() {
    children.clear();
  }

  std::shared_ptr<Service> Router::Node::find_service(int worker_id) {
    return service[worker_id];
  }

  std::string Router::Node::uri() {
    std::string address;
    std::shared_ptr<Node> previous = shared_from_this();

    while (previous != nullptr) {
      address = (previous->is_root() ? "" : "/" + previous->path) + address;
      previous = previous->parent;
    }
    return address;
  }

  std::shared_ptr<Router::Node> Router::Node::start() {
    std::shared_ptr<Node> previous = shared_from_this();

    while (true) {
      if (previous->parent == nullptr)
        return previous;
      else
        previous = previous->parent;
    }
  }

  std::shared_ptr<Router::Node> Router::Node::end() {
    std::shared_ptr<Node> current = shared_from_this();

    while (true) {
      if (current->is_last())
        return current;
      else
        current = current->next();
    }
  }

  bool Router::Node::is_last() {
    return children.empty();
  }

  std::shared_ptr<Router::Node> Router::Node::next() {
    return *(children.begin());
  }

  void Router::Node::print(int level) {
    std::cout << std::string(level*2, ' ') << "/" << path << std::endl;
    for (auto next : children)
      next->print(level+1);
  }

  bool Router::Node::merge(std::shared_ptr<Router::Node> const path) {
    if (Router::Node::equal(path, shared_from_this())) {
      std::vector< std::shared_ptr<Node> > common_paths(path->children.size());
      auto irfit = std::set_intersection(path->children.begin(), path->children.end(), children.begin(), children.end(), common_paths.begin(), Router::Node::less);
      common_paths.resize(irfit - common_paths.begin());

      for (auto next : common_paths) {
        auto common = std::find_if(children.begin(), children.end(), [&next](const std::shared_ptr<Node> c) { return Router::Node::equal(next, c); });

        (*common)->merge(next);
      }

      // see whats new to add
      //   - set difference
      std::vector< std::shared_ptr<Node> > new_paths(path->children.size());
      auto difit = std::set_difference(path->children.begin(), path->children.end(), children.begin(), children.end(), new_paths.begin(), Router::Node::less);
      new_paths.resize(difit - new_paths.begin());

      for (auto p : new_paths) {
        p->parent = shared_from_this();
      }

      children.insert(new_paths.begin(), new_paths.end());
    }

    return true;
  }

  std::shared_ptr<Router::Node> Router::match(std::string const& path, params_map& params) {
    return root->unify(root, path.empty() ? "/" : path, params);
  }

  bool Router::Node::is_splat() {
    return path[0] == '*';
  }

  bool Router::Node::is_root() {
    return parent == nullptr;
  }

  std::shared_ptr<Router::Node> Router::Node::unify(std::shared_ptr<Router::Node> const& root, std::string const& path, params_map& params) {
    std::shared_ptr<Node> match = unify(root, from_path(path), params);

    if (match != nullptr) {
      std::cout << "matched '"<< path <<"' to '"<<match->uri()<<"'\n";
    }

    std::cout << "services " << match->service.size() << std::endl;

    return match;
  }

  std::shared_ptr<Router::Node> Router::Node::unify(std::shared_ptr<Router::Node> const& root, std::shared_ptr<Router::Node> const path, params_map& params) {
    if (Router::Node::unifiable(root, path)) {
      if ((root->is_last() && (path->is_last() || root->is_splat())) ||
          (path->is_last())) {
        return root;
      } else
      if (root->is_last() && !path->is_last()) {
        return nullptr;
      }
    }

    std::shared_ptr<Node> match;

    for (auto next : root->children) {
      if (!Router::Node::unifiable(next, path->next()))
        continue;

      if ((match = unify(next, path->next(), params)) != nullptr) {
        next->inject(path->next(), params);
        return match;
      }
    }

    return nullptr;
  }

  void Router::Node::inject(std::shared_ptr<Router::Node> const& rhs, params_map& params) {
    if (path[0] == ':') {
      params[path.substr(1)] = rhs->path;
    } else
    if (path[0] == '*') {
      int i = 1;
      std::string splat;
      std::shared_ptr<Node> current = rhs;
      while (true) {
        splat += current->path;
        params[std::to_string(i++)] = current->path;
        if (!current->is_last()) {
          splat += "/";
        } else {
          break;
        }
        current = current->next();
      };
      params["0"] = splat;
    }
  }

  std::shared_ptr<Router::Node> Router::Node::from_path(std::string const& p) {
    std::string path = p;

    std::shared_ptr<Node> root = std::make_shared<Node>();
    std::shared_ptr<Node> current = root;

    while (path.find("/") == 0) {
      path.erase(0, 1);
      if (path.empty()) {
        std::cout << "pusty" << std::endl;
        break;
      }

      size_t next = path.find("/");

      std::string name = path;

      if (next != std::string::npos) {
        name = path.substr(0, next);
        path = path.substr(next);
      }

      std::shared_ptr<Node> node = std::make_shared<Node>(name, current);
      current->children.insert(node);
      current = node;
    }

    return root;
  }
}
<commit_msg>root path is working too<commit_after>#include "router.h"
#include "service.h"
#include "lambda_service.h"
#include <string>
#include <iostream>
#include <algorithm>

namespace REST {
  workers_services_vector Router::workers_services;
  Router* Router::pInstance = NULL;
  lambda_patterns* Router::patterns = new lambda_patterns();
  int Router::WORKERS = 256;
  std::shared_ptr<Router::Node> Router::root = std::make_shared<Router::Node>();

  Router::Router() {
    workers_services.resize(WORKERS);

    for (int i = 0; i < WORKERS; i++)
      workers_services[i] = std::make_shared<names_services_map>();
  }

  Router* Router::Instance() {
    if(pInstance == NULL){
      pInstance = new Router();
    }
    return pInstance;
  }

  std::shared_ptr<Service> Router::getResource(std::shared_ptr<Request> request, int worker_id) {
    std::shared_ptr<Node> node = match(request->path, request->parameters);

    if (node == nullptr)
      return NULL;

    std::shared_ptr<Service> service = node->find_service(worker_id);

    node.reset();

    return service;
  }

  void Router::path(std::string const& path, service_lambda lambda) {
    std::shared_ptr<Router::Node> node = Router::Node::from_path(path);
    node->end()->add_service(std::make_shared<LambdaService>(lambda));
    root->merge(node);

    if (node->end()->is_root()) {
      std::cout << "to jes root\n";
    }
  }

  Router::Node::Node(std::string p, std::shared_ptr<Node> const& pr) : path(p), parent(pr) {
  }

  Router::Node::~Node() {
    children.clear();
  }

  std::shared_ptr<Service> Router::Node::find_service(int worker_id) {
    return service[worker_id];
  }

  std::string Router::Node::uri() {
    std::string address;
    std::shared_ptr<Node> previous = shared_from_this();

    while (previous != nullptr) {
      address = (previous->is_root() ? "" : "/" + previous->path) + address;
      previous = previous->parent;
    }
    return address;
  }

  std::shared_ptr<Router::Node> Router::Node::start() {
    std::shared_ptr<Node> previous = shared_from_this();

    while (true) {
      if (previous->parent == nullptr)
        return previous;
      else
        previous = previous->parent;
    }
  }

  std::shared_ptr<Router::Node> Router::Node::end() {
    std::shared_ptr<Node> current = shared_from_this();

    while (true) {
      if (current->is_last())
        return current;
      else
        current = current->next();
    }
  }

  bool Router::Node::is_last() {
    return children.empty();
  }

  std::shared_ptr<Router::Node> Router::Node::next() {
    return *(children.begin());
  }

  void Router::Node::print(int level) {
    std::cout << std::string(level*2, ' ') << "/" << path << std::endl;
    for (auto next : children)
      next->print(level+1);
  }

  bool Router::Node::merge(std::shared_ptr<Router::Node> const path) {
    if (Router::Node::equal(path, shared_from_this())) {
      if (path->service.size() > 0) {
        service = path->service;
        std::cout << "kopiuje service\n";
      }

      std::vector< std::shared_ptr<Node> > common_paths(path->children.size());
      auto irfit = std::set_intersection(path->children.begin(), path->children.end(), children.begin(), children.end(), common_paths.begin(), Router::Node::less);
      common_paths.resize(irfit - common_paths.begin());

      for (auto next : common_paths) {
        auto common = std::find_if(children.begin(), children.end(), [&next](const std::shared_ptr<Node> c) { return Router::Node::equal(next, c); });

        (*common)->merge(next);
      }

      // see whats new to add
      //   - set difference
      std::vector< std::shared_ptr<Node> > new_paths(path->children.size());
      auto difit = std::set_difference(path->children.begin(), path->children.end(), children.begin(), children.end(), new_paths.begin(), Router::Node::less);
      new_paths.resize(difit - new_paths.begin());

      for (auto p : new_paths) {
        p->parent = shared_from_this();
      }

      children.insert(new_paths.begin(), new_paths.end());
    }

    return true;
  }

  std::shared_ptr<Router::Node> Router::match(std::string const& path, params_map& params) {
    return root->unify(root, path.empty() ? "/" : path, params);
  }

  bool Router::Node::is_splat() {
    return path[0] == '*';
  }

  bool Router::Node::is_root() {
    return parent == nullptr;
  }

  std::shared_ptr<Router::Node> Router::Node::unify(std::shared_ptr<Router::Node> const& root, std::string const& path, params_map& params) {
    std::shared_ptr<Node> match = unify(root, from_path(path), params);

    if (match != nullptr) {
      std::cout << "matched '"<< path <<"' to '"<<match->uri()<<"'\n";
    }

    std::cout << "services " << match->service.size() << std::endl;

    return match;
  }

  std::shared_ptr<Router::Node> Router::Node::unify(std::shared_ptr<Router::Node> const& root, std::shared_ptr<Router::Node> const path, params_map& params) {
    if (Router::Node::unifiable(root, path)) {
      if ((root->is_last() && (path->is_last() || root->is_splat())) ||
          (path->is_last())) {
        return root;
      } else
      if (root->is_last() && !path->is_last()) {
        return nullptr;
      }
    }

    std::shared_ptr<Node> match;

    for (auto next : root->children) {
      if (!Router::Node::unifiable(next, path->next()))
        continue;

      if ((match = unify(next, path->next(), params)) != nullptr) {
        next->inject(path->next(), params);
        return match;
      }
    }

    return nullptr;
  }

  void Router::Node::inject(std::shared_ptr<Router::Node> const& rhs, params_map& params) {
    if (path[0] == ':') {
      params[path.substr(1)] = rhs->path;
    } else
    if (path[0] == '*') {
      int i = 1;
      std::string splat;
      std::shared_ptr<Node> current = rhs;
      while (true) {
        splat += current->path;
        params[std::to_string(i++)] = current->path;
        if (!current->is_last()) {
          splat += "/";
        } else {
          break;
        }
        current = current->next();
      };
      params["0"] = splat;
    }
  }

  std::shared_ptr<Router::Node> Router::Node::from_path(std::string const& p) {
    std::string path = p;

    std::shared_ptr<Node> root = std::make_shared<Node>();
    std::shared_ptr<Node> current = root;

    while (path.find("/") == 0) {
      path.erase(0, 1);
      if (path.empty()) {
        std::cout << "pusty" << std::endl;
        break;
      }

      size_t next = path.find("/");

      std::string name = path;

      if (next != std::string::npos) {
        name = path.substr(0, next);
        path = path.substr(next);
      }

      std::shared_ptr<Node> node = std::make_shared<Node>(name, current);
      current->children.insert(node);
      current = node;
    }

    return root;
  }
}
<|endoftext|>


<commit_before>#include "StateComponent.h"
#include "Trigger.h"

#define RESERVE_NUM 10
bool Arthas::StateComponent::init()
{
	//    س?
	m_Transitions.reserve(RESERVENUM);

	return true;
}

void Arthas::StateComponent::enter()
{
}

void Arthas::StateComponent::exit()
{
}

void Arthas::StateComponent::update(int dTime)
{
}

void Arthas::StateComponent::addTransition(Arthas::Transition addTransition)
{
	m_Transitions.push_back(addTransition);
}

void Arthas::StateComponent::removeTransition(Arthas::Transition remTransition)
{
	for (auto& it = m_Transitions.begin(); it != m_Transitions.end(); )
	{

		Arthas::Transition transition = *it;
		if (remTransition.first == transition.first &&
			remTransition.second == transition.second)
		{
			delete transition.first;
			it = m_Transitions.erase(it);
		}
		else
		{
			++it;
		}
	}

}

<commit_msg>aagain<commit_after>#include "Trigger.h"
#include "StateComponent.h"

#define RESERVE_NUM 10
bool Arthas::StateComponent::init()
{
	//    س?
	m_Transitions.reserve(RESERVE_NUM);

	return true;
}

void Arthas::StateComponent::enter()
{
}

void Arthas::StateComponent::exit()
{
}

void Arthas::StateComponent::update(int dTime)
{
}

void Arthas::StateComponent::addTransition(Arthas::Transition addTransition)
{
	m_Transitions.push_back(addTransition);
}

void Arthas::StateComponent::removeTransition(Arthas::Transition remTransition)
{
	for (auto& it = m_Transitions.begin(); it != m_Transitions.end(); )
	{

		Arthas::Transition transition = *it;
		if (remTransition.first == transition.first &&
			remTransition.second == transition.second)
		{
			delete transition.first;
			it = m_Transitions.erase(it);
		}
		else
		{
			++it;
		}
	}

}

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <memory>

#include "..\..\shared\ProblemEngine.h"

int FindSingleElement(const std::shared_ptr<int>& inputArray, int size);

int main(int argc, char * argv[])
{
	ProblemEngine engine("input.txt");
	if (!engine.IsFileOk())
	{
		std::cout << "Unable to open input.txt" << std::endl;
		return 1;
	}

	auto testCases = engine.LoadTestCases();

	for (const auto& testCase : testCases)
	{
		if (testCase.Size % 2 == 0) //only odd inputs accepted
			continue;

		auto singleElement = FindSingleElement(testCase.Data, testCase.Size);

		std::cout << singleElement << std::endl;
	}

	return 0;
}

int FindSingleElement(const std::shared_ptr<int>& inputArray, int size)
{
	return 0;
}<commit_msg>Implement method for finding single element by counting occurrences of each bit across all elements in the input array<commit_after>#include <iostream>
#include <fstream>
#include <memory>

#include "..\..\shared\ProblemEngine.h"

int FindSingleElement(const std::shared_ptr<int>& inputArray, int size);

int main(int argc, char * argv[])
{
	ProblemEngine engine("input.txt");
	if (!engine.IsFileOk())
	{
		std::cout << "Unable to open input.txt" << std::endl;
		return 1;
	}

	auto testCases = engine.LoadTestCases();

	for (const auto& testCase : testCases)
	{
		if (testCase.Size % 2 == 0) //only odd inputs accepted
			continue;

		auto singleElement = FindSingleElement(testCase.Data, testCase.Size);

		std::cout << singleElement << std::endl;
	}

	return 0;
}

int FindSingleElement(const std::shared_ptr<int>& inputArray, int size)
{
	const int INT_SIZE_IN_BITS = 32;

	//this method only works if there are 'n' occurrences of each element other than the single element
	//in the case of this test data, there are two occurrences of every other element since the problem states pairs of people
	const int EXPECTED_ELEMENT_OCCURRENCES = 2;

	int result = 0;
	auto ptr = inputArray.get();

	for (int bit = 0; bit < INT_SIZE_IN_BITS; ++bit)
	{
		int sum = 0;
		int bitMask = 1 << bit;

		for (int i = 0; i < size; ++i)
			if (ptr[i] & bitMask)
				sum++;

		if (sum % EXPECTED_ELEMENT_OCCURRENCES != 0)
			result |= bitMask;
	}

	return result;
}<|endoftext|>


<commit_before>#include <cmath>

#include "light.h"
#include "../ui/TraceUI.h"
extern TraceUI* traceUI;

using namespace std;

double DirectionalLight::distanceAttenuation(const Vec3d& P) const
{
  // distance to light is infinite, so f(di) goes to 0.  Return 1.
  return 1.0;
}

Vec3d DirectionalLight::shadowAttenuation(const ray& r, const Vec3d& p) const
{
  // YOUR CODE HERE:
  // You should implement shadow-handling code here.
  ray R = r;

  isect i;
  if(scene->intersect(R, i)) { //We are occluded
    const Material& m = i.getMaterial();
    if(i.t < RAY_EPSILON) return Vec3d(1,1,1);
    if (m.Trans()){return m.kd(i) %(Vec3d(1,1,1) - m.kt(i));}
    else return Vec3d(0,0,0);
  }else{
    return Vec3d(1,1,1);
  }
}

Vec3d DirectionalLight::getColor() const
{
  return color;
}

Vec3d DirectionalLight::getDirection(const Vec3d& P) const
{
  // for directional light, direction doesn't depend on P
  return -orientation;
}

// Random Sample the sphere
std::tuple<Vec3d,Vec3d> DirectionalLight::firePhoton(void){
  double x = (double)rand()/(double)RAND_MAX;
  double y = (double)rand()/(double)RAND_MAX;
  double z = (double)rand()/(double)RAND_MAX;

  Vec3d sample(x, y, z);
  sample.normalize();

  return std::make_tuple(position, getDirection(sample));
}

double PointLight::distanceAttenuation(const Vec3d& P) const
{

  // YOUR CODE HERE

  // You'll need to modify this method to attenuate the intensity
  // of the light based on the distance between the source and the
  // point P.  For now, we assume no attenuation and just return 1.0
  double d = (P - position).length();
  double falloff = constantTerm + (linearTerm + quadraticTerm*d)*d;
  falloff = (fabs(falloff) < RAY_EPSILON) ? 1.0 : 1.0 / falloff;
  return min( 1.0, falloff );

}

Vec3d PointLight::getColor() const
{
  return color;
}

Vec3d PointLight::getDirection(const Vec3d& P) const
{
  Vec3d ret = position - P;
  ret.normalize();
  return ret;
}

// Random Sample the sphere
std::tuple<Vec3d,Vec3d> PointLight::firePhoton(void){
  double x = (double)rand()/(double)RAND_MAX;
  double y = (double)rand()/(double)RAND_MAX;
  double z = (double)rand()/(double)RAND_MAX;

  Vec3d sample(x, y, z);
  sample.normalize();

  return std::make_tuple(position, getDirection(sample));
}
Vec3d PointLight::shadowAttenuation(const ray& r, const Vec3d& p) const
{
  // YOUR CODE HERE:
  // You should implement shadow-handling code here.
  ray R = r;
  // if(traceUI->isDistributionRayTracing()){
  //   Vec3d mDir = R.getDirection();
  //   Vec3d perterbT = CosWeightedRandomHemiDir2(mDir);
  //   R.d = mDir + perterbT;
  //   R.d.normalize();
  // }

  isect i;
  if(scene->intersect(R, i)) { //We are potentially occluded
    if (i.t < (position - p).length()){
      const Material& m = i.getMaterial();
      if(i.t < RAY_EPSILON) return Vec3d(1,1,1);

      if (m.Trans()){
        return m.kd(i)% (Vec3d(1,1,1)- m.kt(i));
      }
      else{
        return Vec3d(0,0,0);
      }
    }
    else return Vec3d(1,1,1);
  }else{
    return Vec3d(1,1,1);
  }

}
<commit_msg>asdkl;fjsdl<commit_after>#include <cmath>

#include "light.h"
#include "../ui/TraceUI.h"
extern TraceUI* traceUI;

using namespace std;

double DirectionalLight::distanceAttenuation(const Vec3d& P) const
{
  // distance to light is infinite, so f(di) goes to 0.  Return 1.
  return 1.0;
}

Vec3d DirectionalLight::shadowAttenuation(const ray& r, const Vec3d& p) const
{
  // YOUR CODE HERE:
  // You should implement shadow-handling code here.
  ray R = r;

  isect i;
  if(scene->intersect(R, i)) { //We are occluded
    const Material& m = i.getMaterial();
    if(i.t < RAY_EPSILON) return Vec3d(1,1,1);
    if (m.Trans()){return m.kd(i) %(Vec3d(1,1,1) - m.kt(i));}
    else return Vec3d(0,0,0);
  }else{
    return Vec3d(1,1,1);
  }
}

Vec3d DirectionalLight::getColor() const
{
  return color;
}

Vec3d DirectionalLight::getDirection(const Vec3d& P) const
{
  // for directional light, direction doesn't depend on P
  return -orientation;
}

// Random Sample the plane that contains the image of the scene bounds
std::tuple<Vec3d,Vec3d> DirectionalLight::firePhoton(void){
  double x = (double)rand()/(double)RAND_MAX;
  double y = (double)rand()/(double)RAND_MAX;
  double z = (double)rand()/(double)RAND_MAX;

  Vec3d sample(x, y, z);
  sample.normalize();

  return std::make_tuple(position, getDirection(sample));
}

double PointLight::distanceAttenuation(const Vec3d& P) const
{

  // YOUR CODE HERE

  // You'll need to modify this method to attenuate the intensity
  // of the light based on the distance between the source and the
  // point P.  For now, we assume no attenuation and just return 1.0
  double d = (P - position).length();
  double falloff = constantTerm + (linearTerm + quadraticTerm*d)*d;
  falloff = (fabs(falloff) < RAY_EPSILON) ? 1.0 : 1.0 / falloff;
  return min( 1.0, falloff );

}

Vec3d PointLight::getColor() const
{
  return color;
}

Vec3d PointLight::getDirection(const Vec3d& P) const
{
  Vec3d ret = position - P;
  ret.normalize();
  return ret;
}

// Random Sample the sphere
std::tuple<Vec3d,Vec3d> PointLight::firePhoton(void){
  double x = (double)rand()/(double)RAND_MAX;
  double y = (double)rand()/(double)RAND_MAX;
  double z = (double)rand()/(double)RAND_MAX;

  Vec3d sample(x, y, z);
  sample.normalize();

  return std::make_tuple(position, getDirection(sample));
}
Vec3d PointLight::shadowAttenuation(const ray& r, const Vec3d& p) const
{
  // YOUR CODE HERE:
  // You should implement shadow-handling code here.
  ray R = r;
  // if(traceUI->isDistributionRayTracing()){
  //   Vec3d mDir = R.getDirection();
  //   Vec3d perterbT = CosWeightedRandomHemiDir2(mDir);
  //   R.d = mDir + perterbT;
  //   R.d.normalize();
  // }

  isect i;
  if(scene->intersect(R, i)) { //We are potentially occluded
    if (i.t < (position - p).length()){
      const Material& m = i.getMaterial();
      if(i.t < RAY_EPSILON) return Vec3d(1,1,1);

      if (m.Trans()){
        return m.kd(i)% (Vec3d(1,1,1)- m.kt(i));
      }
      else{
        return Vec3d(0,0,0);
      }
    }
    else return Vec3d(1,1,1);
  }else{
    return Vec3d(1,1,1);
  }

}
<|endoftext|>


<commit_before>#include "UT4WebAdmin.h"

#include "Core.h"
#include "Engine.h"
#include "ModuleManager.h"
#include "ModuleInterface.h"

class FUT4WebAdminPlugin : public IModuleInterface
{
	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};

IMPLEMENT_MODULE(FUT4WebAdminPlugin, UT4WebAdmin)

void FUT4WebAdminPlugin::StartupModule()
{
		UUT4WebAdmin* UT4WebAdmin = Cast<UUT4WebAdmin>(StaticConstructObject(UUT4WebAdmin::StaticClass()));
		UT4WebAdmin->Init();

}

void FUT4WebAdminPlugin::ShutdownModule()
{

}

<commit_msg>updated deprecated function<commit_after>#include "UT4WebAdmin.h"

#include "Core.h"
#include "Engine.h"
#include "ModuleManager.h"
#include "ModuleInterface.h"

class FUT4WebAdminPlugin : public IModuleInterface
{
	/** IModuleInterface implementation */
	virtual void StartupModule() override;
	virtual void ShutdownModule() override;
};

IMPLEMENT_MODULE(FUT4WebAdminPlugin, UT4WebAdmin)

void FUT4WebAdminPlugin::StartupModule()
{
		UUT4WebAdmin* UT4WebAdmin = NewObject<UUT4WebAdmin>();
		UT4WebAdmin->Init();

}

void FUT4WebAdminPlugin::ShutdownModule()
{

}

<|endoftext|>