<commit_before>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "spellsuggestionsitem.h"
#include "../Common/defines.h"
#include "../Common/imetadataoperator.h"
#include "../Common/basickeywordsmodel.h"
#include "../Common/basicmetadatamodel.h"

namespace SpellCheck {
    SpellSuggestionsItem::SpellSuggestionsItem(const QString &word, const QString &origin) :
        QAbstractListModel(),
        m_Word(word),
        m_ReplacementOrigin(origin),
        m_ReplacementIndex(-1),
        m_ReplacementSucceeded(false)
    {
    }

    SpellSuggestionsItem::SpellSuggestionsItem(const QString &word):
        QAbstractListModel(),
        m_Word(word),
        m_ReplacementOrigin(word),
        m_ReplacementIndex(-1),
        m_ReplacementSucceeded(false)
    {
    }

    SpellSuggestionsItem::~SpellSuggestionsItem() {

    }

    bool SpellSuggestionsItem::setReplacementIndex(int value) {
        bool result = (value != m_ReplacementIndex) && (value != -1);

        if (result) {
            QVector<int> roles;
            roles << IsSelectedRole;
            int prevIndexToUpdate = m_ReplacementIndex;
            m_ReplacementIndex = value;

            if (prevIndexToUpdate != -1) {
                QModelIndex prev = this->index(prevIndexToUpdate);
                emit dataChanged(prev, prev, roles);
            }

            QModelIndex curr = this->index(value);
            emit dataChanged(curr, curr, roles);
        } else {
            if ((value == m_ReplacementIndex) ||
                    (value == -1 && m_ReplacementIndex != -1)) {
                int prevIndexToUpdate = m_ReplacementIndex;
                m_ReplacementIndex = -1;

                QModelIndex prev = this->index(prevIndexToUpdate);
                QVector<int> roles;
                roles << IsSelectedRole;
                emit dataChanged(prev, prev, roles);
                result = true;
            }
        }

        return result;
    }

    void SpellSuggestionsItem::setSuggestions(const QStringList &suggestions) {
        beginResetModel();
        m_Suggestions.clear();
        m_Suggestions.append(suggestions);
        endResetModel();
    }

    int SpellSuggestionsItem::rowCount(const QModelIndex &parent) const {
        Q_UNUSED(parent);
        return m_Suggestions.length();
    }

    QVariant SpellSuggestionsItem::data(const QModelIndex &index, int role) const {
        int row = index.row();
        if (row < 0 || row >= m_Suggestions.length()) { return QVariant(); }

        switch (role) {
        case SuggestionRole:
            return m_Suggestions.at(row);
        case IsSelectedRole:
            return (m_ReplacementIndex == row);
        default:
            return QVariant();
        }
    }

    Qt::ItemFlags SpellSuggestionsItem::flags(const QModelIndex &index) const {
        int row = index.row();
        if (row < 0 || row >= m_Suggestions.length()) {
            return Qt::ItemIsEnabled;
        }

        return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
    }

    bool SpellSuggestionsItem::setData(const QModelIndex &index, const QVariant &value, int role) {
        int row = index.row();
        if (row < 0 || row >= m_Suggestions.length()) return false;

        bool result = false;

        switch (role) {
        case EditReplacementIndexRole:
            result = setReplacementIndex(value.toInt());
            break;
        default:
            return false;
        }

        return result;
    }

    QHash<int, QByteArray> SpellSuggestionsItem::roleNames() const {
        QHash<int, QByteArray> roles;
        roles[SuggestionRole] = "suggestion";
        roles[IsSelectedRole] = "isselected";
        roles[EditReplacementIndexRole] = "editreplacementindex";
        return roles;
    }

    KeywordSpellSuggestions::KeywordSpellSuggestions(const QString &keyword, int originalIndex, const QString &origin) :
        SpellSuggestionsItem(keyword, origin),
        m_OriginalIndex(originalIndex),
        m_ReplaceResult(Common::KeywordReplaceResult::Unknown)
    {
    }

    KeywordSpellSuggestions::KeywordSpellSuggestions(const QString &keyword, int originalIndex):
        SpellSuggestionsItem(keyword),
        m_OriginalIndex(originalIndex),
        m_ReplaceResult(Common::KeywordReplaceResult::Unknown)
    {
    }

    KeywordSpellSuggestions::~KeywordSpellSuggestions() {
    }

    void KeywordSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void KeywordSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        LOG_INFO << word << "-->" << replacement;
        auto *item = getMetadataOperator();
        Common::KeywordReplaceResult result = item->fixKeywordSpelling(m_OriginalIndex, word, replacement);
        setReplacementSucceeded(result == Common::KeywordReplaceResult::Succeeded);
        m_ReplaceResult = result;
    }

    DescriptionSpellSuggestions::DescriptionSpellSuggestions(const QString &word):
        SpellSuggestionsItem(word)
    {
    }

    DescriptionSpellSuggestions::~DescriptionSpellSuggestions() {
    }

    void DescriptionSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void DescriptionSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        LOG_INFO << word << "-->" << replacement;
        auto *item = getMetadataOperator();
        bool success = item->fixDescriptionSpelling(word, replacement);
        setReplacementSucceeded(success);

        if (!success) {
            LOG_WARNING << "Failed to replace in description" << word << "to" << replacement;
        }
    }

    TitleSpellSuggestions::TitleSpellSuggestions(const QString &word):
        SpellSuggestionsItem(word)
    {
    }

    TitleSpellSuggestions::~TitleSpellSuggestions() {
    }

    void TitleSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void TitleSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        LOG_INFO << word << "-->" << replacement;
        auto *item = getMetadataOperator();
        bool success = item->fixTitleSpelling(word, replacement);
        setReplacementSucceeded(success);

        if (!success) {
            LOG_WARNING << "Failed to replace in title" << word << "to" << replacement;
        }
    }

    CombinedSpellSuggestions::CombinedSpellSuggestions(const QString &word, std::vector<std::shared_ptr<SpellSuggestionsItem> > &suggestions):
        SpellSuggestionsItem(word, tr("multireplace")),
        m_SpellSuggestions(std::move(suggestions))
    {
        Q_ASSERT(!m_SpellSuggestions.empty());
    }

    CombinedSpellSuggestions::~CombinedSpellSuggestions() {
    }

    std::vector<std::shared_ptr<KeywordSpellSuggestions> > CombinedSpellSuggestions::getKeywordsDuplicateSuggestions() const {
        std::vector<std::shared_ptr<KeywordSpellSuggestions> > keywordsSuggestions;

        for (auto &item: m_SpellSuggestions) {
            std::shared_ptr<KeywordSpellSuggestions> keywordsItem = std::dynamic_pointer_cast<KeywordSpellSuggestions>(item);
            if (keywordsItem && keywordsItem->isPotentialDuplicate()) {
                keywordsSuggestions.push_back(keywordsItem);
            }
        }

        return keywordsSuggestions;
    }

    void CombinedSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void CombinedSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        size_t size = m_SpellSuggestions.size();
        LOG_INFO << size << "item(s)";
        bool anySucceeded = false;

        for (size_t i = 0; i < size; ++i) {
            auto &suggestionItem = m_SpellSuggestions.at(i);
            suggestionItem->replaceToSuggested(word, replacement);

            LOG_INTEGRATION_TESTS << i << "item's result is:" << suggestionItem->getReplacementSucceeded();

            if (suggestionItem->getReplacementSucceeded()) {
                anySucceeded = true;
            }
        }

        setReplacementSucceeded(anySucceeded);
    }
}
<commit_msg>Cosmetic improvements [ci skip]<commit_after>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014-2017 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "spellsuggestionsitem.h"
#include "../Common/defines.h"
#include "../Common/imetadataoperator.h"
#include "../Common/basickeywordsmodel.h"
#include "../Common/basicmetadatamodel.h"

namespace SpellCheck {
    SpellSuggestionsItem::SpellSuggestionsItem(const QString &word, const QString &origin) :
        QAbstractListModel(),
        m_MetadataOperator(nullptr),
        m_Word(word),
        m_ReplacementOrigin(origin),
        m_ReplacementIndex(-1),
        m_ReplacementSucceeded(false)
    {
    }

    SpellSuggestionsItem::SpellSuggestionsItem(const QString &word):
        QAbstractListModel(),
        m_MetadataOperator(nullptr),
        m_Word(word),
        m_ReplacementOrigin(word),
        m_ReplacementIndex(-1),
        m_ReplacementSucceeded(false)
    {
    }

    SpellSuggestionsItem::~SpellSuggestionsItem() {

    }

    bool SpellSuggestionsItem::setReplacementIndex(int value) {
        bool result = (value != m_ReplacementIndex) && (value != -1);

        if (result) {
            QVector<int> roles;
            roles << IsSelectedRole;
            int prevIndexToUpdate = m_ReplacementIndex;
            m_ReplacementIndex = value;

            if (prevIndexToUpdate != -1) {
                QModelIndex prev = this->index(prevIndexToUpdate);
                emit dataChanged(prev, prev, roles);
            }

            QModelIndex curr = this->index(value);
            emit dataChanged(curr, curr, roles);
        } else {
            if ((value == m_ReplacementIndex) ||
                    (value == -1 && m_ReplacementIndex != -1)) {
                int prevIndexToUpdate = m_ReplacementIndex;
                m_ReplacementIndex = -1;

                QModelIndex prev = this->index(prevIndexToUpdate);
                QVector<int> roles;
                roles << IsSelectedRole;
                emit dataChanged(prev, prev, roles);
                result = true;
            }
        }

        return result;
    }

    void SpellSuggestionsItem::setSuggestions(const QStringList &suggestions) {
        beginResetModel();
        m_Suggestions.clear();
        m_Suggestions.append(suggestions);
        endResetModel();
    }

    int SpellSuggestionsItem::rowCount(const QModelIndex &parent) const {
        Q_UNUSED(parent);
        return m_Suggestions.length();
    }

    QVariant SpellSuggestionsItem::data(const QModelIndex &index, int role) const {
        int row = index.row();
        if (row < 0 || row >= m_Suggestions.length()) { return QVariant(); }

        switch (role) {
        case SuggestionRole:
            return m_Suggestions.at(row);
        case IsSelectedRole:
            return (m_ReplacementIndex == row);
        default:
            return QVariant();
        }
    }

    Qt::ItemFlags SpellSuggestionsItem::flags(const QModelIndex &index) const {
        int row = index.row();
        if (row < 0 || row >= m_Suggestions.length()) {
            return Qt::ItemIsEnabled;
        }

        return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
    }

    bool SpellSuggestionsItem::setData(const QModelIndex &index, const QVariant &value, int role) {
        int row = index.row();
        if (row < 0 || row >= m_Suggestions.length()) return false;

        bool result = false;

        switch (role) {
        case EditReplacementIndexRole:
            result = setReplacementIndex(value.toInt());
            break;
        default:
            return false;
        }

        return result;
    }

    QHash<int, QByteArray> SpellSuggestionsItem::roleNames() const {
        QHash<int, QByteArray> roles;
        roles[SuggestionRole] = "suggestion";
        roles[IsSelectedRole] = "isselected";
        roles[EditReplacementIndexRole] = "editreplacementindex";
        return roles;
    }

    KeywordSpellSuggestions::KeywordSpellSuggestions(const QString &keyword, int originalIndex, const QString &origin) :
        SpellSuggestionsItem(keyword, origin),
        m_OriginalIndex(originalIndex),
        m_ReplaceResult(Common::KeywordReplaceResult::Unknown)
    {
    }

    KeywordSpellSuggestions::KeywordSpellSuggestions(const QString &keyword, int originalIndex):
        SpellSuggestionsItem(keyword),
        m_OriginalIndex(originalIndex),
        m_ReplaceResult(Common::KeywordReplaceResult::Unknown)
    {
    }

    KeywordSpellSuggestions::~KeywordSpellSuggestions() {
    }

    void KeywordSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void KeywordSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        LOG_INFO << word << "-->" << replacement;
        auto *item = getMetadataOperator();
        Common::KeywordReplaceResult result = item->fixKeywordSpelling(m_OriginalIndex, word, replacement);
        setReplacementSucceeded(result == Common::KeywordReplaceResult::Succeeded);
        m_ReplaceResult = result;
    }

    DescriptionSpellSuggestions::DescriptionSpellSuggestions(const QString &word):
        SpellSuggestionsItem(word)
    {
    }

    DescriptionSpellSuggestions::~DescriptionSpellSuggestions() {
    }

    void DescriptionSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void DescriptionSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        LOG_INFO << word << "-->" << replacement;
        auto *item = getMetadataOperator();
        bool success = item->fixDescriptionSpelling(word, replacement);
        setReplacementSucceeded(success);

        if (!success) {
            LOG_WARNING << "Failed to replace in description" << word << "to" << replacement;
        }
    }

    TitleSpellSuggestions::TitleSpellSuggestions(const QString &word):
        SpellSuggestionsItem(word)
    {
    }

    TitleSpellSuggestions::~TitleSpellSuggestions() {
    }

    void TitleSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void TitleSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        LOG_INFO << word << "-->" << replacement;
        auto *item = getMetadataOperator();
        bool success = item->fixTitleSpelling(word, replacement);
        setReplacementSucceeded(success);

        if (!success) {
            LOG_WARNING << "Failed to replace in title" << word << "to" << replacement;
        }
    }

    CombinedSpellSuggestions::CombinedSpellSuggestions(const QString &word, std::vector<std::shared_ptr<SpellSuggestionsItem> > &suggestions):
        SpellSuggestionsItem(word, tr("multireplace")),
        m_SpellSuggestions(std::move(suggestions))
    {
        Q_ASSERT(!m_SpellSuggestions.empty());
    }

    CombinedSpellSuggestions::~CombinedSpellSuggestions() {
    }

    std::vector<std::shared_ptr<KeywordSpellSuggestions> > CombinedSpellSuggestions::getKeywordsDuplicateSuggestions() const {
        std::vector<std::shared_ptr<KeywordSpellSuggestions> > keywordsSuggestions;

        for (auto &item: m_SpellSuggestions) {
            std::shared_ptr<KeywordSpellSuggestions> keywordsItem = std::dynamic_pointer_cast<KeywordSpellSuggestions>(item);
            if (keywordsItem && keywordsItem->isPotentialDuplicate()) {
                keywordsSuggestions.push_back(keywordsItem);
            }
        }

        return keywordsSuggestions;
    }

    void CombinedSpellSuggestions::replaceToSuggested() {
        if (anyReplacementSelected()) {
            const QString &word = getWord();
            const QString &replacement = getReplacement();
            this->replaceToSuggested(word, replacement);
        }
    }

    void CombinedSpellSuggestions::replaceToSuggested(const QString &word, const QString &replacement) {
        size_t size = m_SpellSuggestions.size();
        LOG_INFO << size << "item(s)";
        bool anySucceeded = false;

        for (size_t i = 0; i < size; ++i) {
            auto &suggestionItem = m_SpellSuggestions.at(i);
            suggestionItem->replaceToSuggested(word, replacement);

            LOG_INTEGRATION_TESTS << i << "item's result is:" << suggestionItem->getReplacementSucceeded();

            if (suggestionItem->getReplacementSucceeded()) {
                anySucceeded = true;
            }
        }

        setReplacementSucceeded(anySucceeded);
    }
}
<|endoftext|>


<commit_before>#include "cnn/nodes.h"
#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/timing.h"
#include "cnn/rnn.h"
#include "cnn/gru.h"
#include "cnn/lstm.h"
#include "cnn/dglstm.h"
#include "cnn/dict.h"
#include "cnn/expr.h"
#include "cnn/cnn-helper.h"
#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

using namespace std;
using namespace cnn;

long LAYERS = 2;
long INPUT_DIM = 8;  //256
long HIDDEN_DIM = 24;  // 1024
long VOCAB_SIZE = 0;

cnn::Dict d;
int kSOS;
int kEOS;

template <class Builder>
struct RNNLanguageModel {
  LookupParameters* p_c;
  Parameters* p_R;
  Parameters* p_bias;
  Builder builder;
  explicit RNNLanguageModel(Model& model) : builder(LAYERS, INPUT_DIM, HIDDEN_DIM, &model) {
    p_c = model.add_lookup_parameters(VOCAB_SIZE, {INPUT_DIM});
    p_R = model.add_parameters({VOCAB_SIZE, HIDDEN_DIM});
    p_bias = model.add_parameters({VOCAB_SIZE});
  }

  // return Expression of total loss
  Expression BuildLMGraph(const vector<int>& sent, ComputationGraph& cg) {
    const unsigned slen = sent.size() - 1;
    builder.new_graph(cg);  // reset RNN builder for new graph
    builder.start_new_sequence();
    Expression i_R = parameter(cg, p_R); // hidden -> word rep parameter
    Expression i_bias = parameter(cg, p_bias);  // word bias
    vector<Expression> errs;
    for (unsigned t = 0; t < slen; ++t) {
      Expression i_x_t = lookup(cg, p_c, sent[t]);
      // y_t = RNN(x_t)
      Expression i_y_t = builder.add_input(i_x_t);
      Expression i_r_t =  i_bias + i_R * i_y_t;

      // we can easily look at intermidiate values
//      std::vector<float> r_t = as_vector(i_r_t.value());
  //    for (float f : r_t) cout << f << " "; cout << endl;
    //  cout << "[" << as_scalar(pick(i_r_t, sent[t+1]).value()) << "]" << endl;

      // LogSoftmax followed by PickElement can be written in one step
      // using PickNegLogSoftmax
#if 0
      Expression i_ydist = logsoftmax(i_r_t);
      errs.push_back(pick(i_ydist, sent[t+1]));
#if 0
      Expression i_ydist = softmax(i_r_t);
      i_ydist = log(i_ydist)
      errs.push_back(pick(i_ydist, sent[t+1]));
#endif
#else
      Expression i_err = pickneglogsoftmax(i_r_t, sent[t+1]);
      errs.push_back(i_err);
#endif
    }
    Expression i_nerr = sum(errs);
#if 0
    return -i_nerr;
#else
    return i_nerr;
#endif
  }

  // return Expression for total loss
  void RandomSample(int max_len = 150) {
    cerr << endl;
    ComputationGraph cg;
    builder.new_graph(cg);  // reset RNN builder for new graph
    builder.start_new_sequence();

    Expression i_R = parameter(cg, p_R);
    Expression i_bias = parameter(cg, p_bias);
    vector<Expression> errs;
    int len = 0;
    int cur = kSOS;
    while(len < max_len && cur != kEOS) {
      ++len;
      Expression i_x_t = lookup(cg, p_c, cur);
      // y_t = RNN(x_t)
      Expression i_y_t = builder.add_input(i_x_t);
      Expression i_r_t = i_bias + i_R * i_y_t;

      Expression ydist = softmax(i_r_t);

      unsigned w = 0;
      while (w == 0 || (int)w == kSOS) {
        auto dist = as_vector(cg.incremental_forward());
        double p = rand01();
        for (; w < dist.size(); ++w) {
          p -= dist[w];
          if (p < 0.0) { break; }
        }
        if (w == dist.size()) w = kEOS;
      }
      cerr << (len == 1 ? "" : " ") << d.Convert(w);
      cur = w;
    }
    cerr << endl;
  }
};

template <class LM_t>
void train(Model &model, LM_t &lm,
    const vector<vector<int>>& training,
    const vector<vector<int>>& dev,
    Trainer *sgd, const string& fname,
    bool randomSample)
{
    double best = 9e+99;
    unsigned report_every_i = 50;
    unsigned dev_every_i_reports = 500;
    unsigned si = training.size();
    vector<unsigned> order(training.size());
    for (unsigned i = 0; i < order.size(); ++i) order[i] = i;
    bool first = true;
    int report = 0;
    unsigned lines = 0;
    while (1) {
        Timer iteration("completed in");
        double loss = 0;
        unsigned chars = 0;
        for (unsigned i = 0; i < report_every_i; ++i) {
            if (si == training.size()) {
                si = 0;
                if (first) { first = false; }
                else { sgd->update_epoch(); }
                cerr << "**SHUFFLE\n";
                shuffle(order.begin(), order.end(), *rndeng);
            }

            // build graph for this instance
            ComputationGraph cg;
            auto& sent = training[order[si]];
            chars += sent.size() - 1;
            ++si;
            lm.BuildLMGraph(sent, cg);
            loss += as_scalar(cg.forward());
            cg.backward();
            sgd->update();
            ++lines;
        }
        sgd->status();
        cerr << " E = " << (loss / chars) << " ppl=" << exp(loss / chars) << ' ';

        if (randomSample)
            lm.RandomSample();

        // show score on dev data?
        report++;
        if (report % dev_every_i_reports == 0) {
            double dloss = 0;
            int dchars = 0;
            for (auto& sent : dev) {
                ComputationGraph cg;
                lm.BuildLMGraph(sent, cg);
                dloss += as_scalar(cg.forward());
                dchars += sent.size() - 1;
            }
            if (dloss < best) {
                best = dloss;
                ofstream out(fname);
                boost::archive::text_oarchive oa(out);
                oa << model;
            }
            else{
                sgd->eta *= 0.5;
            }
            cerr << "\n***TEST E = " << (dloss / dchars) << " ppl=" << exp(dloss / dchars) << ' ';
        }
    }
}

template <class LM_t>
void testcorpus(Model &model, LM_t &lm,
    const vector<vector<int>>& dev)
{
    unsigned lines = 0;
    double dloss = 0;
    int dchars = 0;
    for (auto& sent : dev) {
        ComputationGraph cg;
        lm.BuildLMGraph(sent, cg);
        dloss += as_scalar(cg.forward());
        dchars += sent.size() - 1;
    }

    cerr << "\n***DEV [epoch=" << (lines / (double)dev.size()) << "] E = " << (dloss / dchars) << " ppl=" << exp(dloss / dchars) << ' ';
}

void initialise(Model &model, const string &filename)
{
    cerr << "Initialising model parameters from file: " << filename << endl;
    ifstream in(filename);
    boost::archive::text_iarchive ia(in);
    ia >> model;
}

int main(int argc, char** argv) {
  cnn::Initialize(argc, argv);

  // command line processing
  using namespace boost::program_options;
  variables_map vm;
  options_description opts("Allowed options");
  opts.add_options()
      ("help", "print help message")
      ("seed,s", value<int>()->default_value(217), "random seed number")
      ("train,t", value<string>(), "file containing training sentences")
      ("devel,d", value<string>(), "file containing development sentences.")
      ("test,T", value<string>(), "file containing testing source sentences")
      ("initialise,i", value<string>(), "load initial parameters from file")
      ("parameters,p", value<string>(), "save best parameters to this file")
      ("layers,l", value<int>()->default_value(LAYERS), "use <num> layers for RNN components")
      ("hidden,h", value<int>()->default_value(HIDDEN_DIM), "use <num> dimensions for recurrent hidden states")
      ("gru", "use Gated Recurrent Unit (GRU) for recurrent structure; default RNN")
      ("lstm", "use Long Short Term Memory (GRU) for recurrent structure; default RNN")
      ("dglstm", "use depth-gated LSTM for recurrent structure; default RNN")
      ("dglstmem", "use depth-gated LSTM with external memory for recurrent structure; default RNN")
      ("nmn", "use NMN type method with external memory for recurrent structure; default RNN")
      ("verbose,v", "be extremely chatty")
      ("generate,g", value<bool>()->default_value(false), "generate random samples")
      ;
  store(parse_command_line(argc, argv, opts), vm);

  string flavour;
  if (vm.count("gru"))	flavour = "gru";
  else if (vm.count("lstm"))	flavour = "lstm";
  else if (vm.count("rnnem"))	flavour = "rnnem";
  else if (vm.count("dglstm")) flavour = "dglstm";
  else if (vm.count("nmn")) flavour = "nmn";
  else			flavour = "rnn";

  LAYERS = vm["layers"].as<int>();
  HIDDEN_DIM = vm["hidden"].as<int>();

  bool generateSample = false;
  generateSample = vm["generate"].as<bool>();

  string fname;
  if (vm.count("parameters")) {
      fname = vm["parameters"].as<string>();
  }
  else {
      ostringstream os;
      os << "lm"
          << '_' << LAYERS
          << '_' << HIDDEN_DIM
          << '_' << flavour
          << "-pid" << getpid() << ".params";
      fname = os.str();
  }

  cerr << "Parameters will be written to: " << fname << endl;

  if (vm.count("help") || vm.count("train") != 1 || (vm.count("devel") != 1 && vm.count("test") != 1)) {
      cout << opts << "\n";
      return 1;
  }

  kSOS = d.Convert("<s>");
  kEOS = d.Convert("</s>");
  vector<vector<int>> training, dev, test;
  string line;
  int tlc = 0;
  int ttoks = 0;

  string infile = vm["train"].as<string>();
  cerr << "Reading training data from " << infile << "...\n";

  {
    ifstream in(infile);
    assert(in);
    while(getline(in, line)) {
      ++tlc;
      training.push_back(ReadSentence(line, &d));
      ttoks += training.back().size();
      if (training.back().front() != kSOS && training.back().back() != kEOS) {
        cerr << "Training sentence in " << infile << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << tlc << " lines, " << ttoks << " tokens, " << d.size() << " types\n";
  }
  d.Freeze(); // no new word types allowed
  VOCAB_SIZE = d.size();

  if (vm.count("devel") > 0)
  {
      int dlc = 0;
      int dtoks = 0;
      string devfile = vm["devel"].as<string>();
      cerr << "Reading training data from " << devfile << "...\n";
      {
          ifstream in(devfile);
          assert(in);
          while (getline(in, line)) {
              ++dlc;
              dev.push_back(ReadSentence(line, &d));
              dtoks += dev.back().size();
              if (dev.back().front() != kSOS && dev.back().back() != kEOS) {
                  cerr << "Dev sentence in " << devfile << ":" << tlc << " didn't start or end with <s>, </s>\n";
                  abort();
              }
          }
          cerr << dlc << " lines, " << dtoks << " tokens\n";
      }
  }

  Model model;
  bool use_momentum = false;
  Trainer* sgd = nullptr;
  //if (use_momentum)
  //  sgd = new MomentumSGDTrainer(&model);
  //else
  sgd = new SimpleSGDTrainer(&model);

  if (vm.count("test") == 0)
  {
      if (vm.count("lstm")) {
          cerr << "%% Using LSTM recurrent units" << endl;
          RNNLanguageModel<LSTMBuilder> lm(model);
          train(model, lm, training, dev, sgd, fname, generateSample);
      }
      else if (vm.count("dglstm")) {
          cerr << "%% Using DGLSTM recurrent units" << endl;
          RNNLanguageModel<DGLSTMBuilder> lm(model);
          train(model, lm, training, dev, sgd, fname, generateSample);
      }
  }
  else
  {
      string testfile = vm["test"].as<string>();
      int dlc = 0;
      int dtoks = 0;
      cerr << "Reading training data from " << testfile << "...\n";
      {
          ifstream in(testfile);
          assert(in);
          while (getline(in, line)) {
              ++dlc;
              test.push_back(ReadSentence(line, &d));
              dtoks += test.back().size();
              if (test.back().front() != kSOS && test.back().back() != kEOS) {
                  cerr << "Dev sentence in " << testfile << ":" << tlc << " didn't start or end with <s>, </s>\n";
                  abort();
              }
          }
          cerr << dlc << " lines, " << dtoks << " tokens\n";
      }

      if (vm.count("test"))
      {
          if (vm.count("lstm")){
              cerr << "%% using LSTM recurrent units" << endl;
              RNNLanguageModel<LSTMBuilder> lm(model);
              if (vm.count("initialise"))
                  initialise(model, vm["initialise"].as<string>());
              testcorpus(model, lm, test);
          }
          if (vm.count("dglstm")){
              cerr << "%% using DGLSTM recurrent units" << endl;
              RNNLanguageModel<DGLSTMBuilder> lm(model);
              if (vm.count("initialise"))
                  initialise(model, vm["initialise"].as<string>());
              testcorpus(model, lm, test);
          }
      }
  }

  //RNNLanguageModel<SimpleRNNBuilder> lm(model);
  if (argc == 4) {
    string fname = argv[3];
    ifstream in(fname);
    boost::archive::text_iarchive ia(in);
    ia >> model;
  }

  delete sgd;
}

<commit_msg>fixed rnnlm2 serialization bug. need to close file handler after searialization<commit_after>#include "cnn/nodes.h"
#include "cnn/cnn.h"
#include "cnn/training.h"
#include "cnn/timing.h"
#include "cnn/rnn.h"
#include "cnn/gru.h"
#include "cnn/lstm.h"
#include "cnn/dglstm.h"
#include "cnn/dict.h"
#include "cnn/expr.h"
#include "cnn/cnn-helper.h"
#include <iostream>
#include <fstream>
#include <sstream>

#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

using namespace std;
using namespace cnn;

long LAYERS = 2;
long INPUT_DIM = 8;  //256
long HIDDEN_DIM = 24;  // 1024
long VOCAB_SIZE = 0;

cnn::Dict d;
int kSOS;
int kEOS;

template <class Builder>
struct RNNLanguageModel {
  LookupParameters* p_c;
  Parameters* p_R;
  Parameters* p_bias;
  Builder builder;
  explicit RNNLanguageModel(Model& model) : builder(LAYERS, INPUT_DIM, HIDDEN_DIM, &model) {
    p_c = model.add_lookup_parameters(VOCAB_SIZE, {INPUT_DIM});
    p_R = model.add_parameters({VOCAB_SIZE, HIDDEN_DIM});
    p_bias = model.add_parameters({VOCAB_SIZE});
  }

  // return Expression of total loss
  Expression BuildLMGraph(const vector<int>& sent, ComputationGraph& cg) {
    const unsigned slen = sent.size() - 1;
    builder.new_graph(cg);  // reset RNN builder for new graph
    builder.start_new_sequence();
    Expression i_R = parameter(cg, p_R); // hidden -> word rep parameter
    Expression i_bias = parameter(cg, p_bias);  // word bias
    vector<Expression> errs;
    for (unsigned t = 0; t < slen; ++t) {
      Expression i_x_t = lookup(cg, p_c, sent[t]);
      // y_t = RNN(x_t)
      Expression i_y_t = builder.add_input(i_x_t);
      Expression i_r_t =  i_bias + i_R * i_y_t;

      // we can easily look at intermidiate values
//      std::vector<float> r_t = as_vector(i_r_t.value());
  //    for (float f : r_t) cout << f << " "; cout << endl;
    //  cout << "[" << as_scalar(pick(i_r_t, sent[t+1]).value()) << "]" << endl;

      // LogSoftmax followed by PickElement can be written in one step
      // using PickNegLogSoftmax
#if 0
      Expression i_ydist = logsoftmax(i_r_t);
      errs.push_back(pick(i_ydist, sent[t+1]));
#if 0
      Expression i_ydist = softmax(i_r_t);
      i_ydist = log(i_ydist)
      errs.push_back(pick(i_ydist, sent[t+1]));
#endif
#else
      Expression i_err = pickneglogsoftmax(i_r_t, sent[t+1]);
      errs.push_back(i_err);
#endif
    }
    Expression i_nerr = sum(errs);
#if 0
    return -i_nerr;
#else
    return i_nerr;
#endif
  }

  // return Expression for total loss
  void RandomSample(int max_len = 150) {
    cerr << endl;
    ComputationGraph cg;
    builder.new_graph(cg);  // reset RNN builder for new graph
    builder.start_new_sequence();

    Expression i_R = parameter(cg, p_R);
    Expression i_bias = parameter(cg, p_bias);
    vector<Expression> errs;
    int len = 0;
    int cur = kSOS;
    while(len < max_len && cur != kEOS) {
      ++len;
      Expression i_x_t = lookup(cg, p_c, cur);
      // y_t = RNN(x_t)
      Expression i_y_t = builder.add_input(i_x_t);
      Expression i_r_t = i_bias + i_R * i_y_t;

      Expression ydist = softmax(i_r_t);

      unsigned w = 0;
      while (w == 0 || (int)w == kSOS) {
        auto dist = as_vector(cg.incremental_forward());
        double p = rand01();
        for (; w < dist.size(); ++w) {
          p -= dist[w];
          if (p < 0.0) { break; }
        }
        if (w == dist.size()) w = kEOS;
      }
      cerr << (len == 1 ? "" : " ") << d.Convert(w);
      cur = w;
    }
    cerr << endl;
  }
};

template <class LM_t>
void train(Model &model, LM_t &lm,
    const vector<vector<int>>& training,
    const vector<vector<int>>& dev,
    Trainer *sgd, const string& fname,
    bool randomSample)
{
    double best = 9e+99;
    unsigned report_every_i = 50;
    unsigned dev_every_i_reports = 500;
    unsigned si = training.size();
    vector<unsigned> order(training.size());
    for (unsigned i = 0; i < order.size(); ++i) order[i] = i;
    bool first = true;
    int report = 0;
    unsigned lines = 0;

    ofstream out(fname, ofstream::out);
    boost::archive::text_oarchive oa(out);
    oa << model;
    out.close();

    while (1) {
        Timer iteration("completed in");
        double loss = 0;
        unsigned chars = 0;
        for (unsigned i = 0; i < report_every_i; ++i) {
            if (si == training.size()) {
                si = 0;
                if (first) { first = false; }
                else { sgd->update_epoch(); }
                cerr << "**SHUFFLE\n";
                shuffle(order.begin(), order.end(), *rndeng);
            }

            // build graph for this instance
            ComputationGraph cg;
            auto& sent = training[order[si]];
            chars += sent.size() - 1;
            ++si;
            lm.BuildLMGraph(sent, cg);
            loss += as_scalar(cg.forward());
            cg.backward();
            sgd->update();
            ++lines;
        }
        sgd->status();
        cerr << " E = " << (loss / chars) << " ppl=" << exp(loss / chars) << ' ';

        if (randomSample)
            lm.RandomSample();

        // show score on dev data?
        report++;
        if (report % dev_every_i_reports == 0) {
            double dloss = 0;
            int dchars = 0;
            for (auto& sent : dev) {
                ComputationGraph cg;
                lm.BuildLMGraph(sent, cg);
                dloss += as_scalar(cg.forward());
                dchars += sent.size() - 1;
            }
            if (dloss < best) {
                best = dloss;
                ofstream out(fname, ofstream::out);
                boost::archive::text_oarchive oa(out);
                oa << model;
            }
            else{
                sgd->eta *= 0.5;
            }
            cerr << "\n***TEST E = " << (dloss / dchars) << " ppl=" << exp(dloss / dchars) << ' ';
        }
    }
}

template <class LM_t>
void testcorpus(Model &model, LM_t &lm,
    const vector<vector<int>>& dev)
{
    unsigned lines = 0;
    double dloss = 0;
    int dchars = 0;
    for (auto& sent : dev) {
        ComputationGraph cg;
        lm.BuildLMGraph(sent, cg);
        dloss += as_scalar(cg.forward());
        dchars += sent.size() - 1;
    }

    cerr << "\n***DEV [epoch=" << (lines / (double)dev.size()) << "] E = " << (dloss / dchars) << " ppl=" << exp(dloss / dchars) << ' ';
}

void initialise(Model &model, const string &filename)
{
    cerr << "Initialising model parameters from file: " << filename << endl;
    ifstream in(filename, ifstream::in);
    boost::archive::text_iarchive ia(in);
    ia >> model;
}

int main(int argc, char** argv) {
  cnn::Initialize(argc, argv);

  // command line processing
  using namespace boost::program_options;
  variables_map vm;
  options_description opts("Allowed options");
  opts.add_options()
      ("help", "print help message")
      ("seed,s", value<int>()->default_value(217), "random seed number")
      ("train,t", value<string>(), "file containing training sentences")
      ("devel,d", value<string>(), "file containing development sentences.")
      ("test,T", value<string>(), "file containing testing source sentences")
      ("initialise,i", value<string>(), "load initial parameters from file")
      ("parameters,p", value<string>(), "save best parameters to this file")
      ("layers,l", value<int>()->default_value(LAYERS), "use <num> layers for RNN components")
      ("hidden,h", value<int>()->default_value(HIDDEN_DIM), "use <num> dimensions for recurrent hidden states")
      ("gru", "use Gated Recurrent Unit (GRU) for recurrent structure; default RNN")
      ("lstm", "use Long Short Term Memory (GRU) for recurrent structure; default RNN")
      ("dglstm", "use depth-gated LSTM for recurrent structure; default RNN")
      ("dglstmem", "use depth-gated LSTM with external memory for recurrent structure; default RNN")
      ("nmn", "use NMN type method with external memory for recurrent structure; default RNN")
      ("verbose,v", "be extremely chatty")
      ("generate,g", value<bool>()->default_value(false), "generate random samples")
      ;
  store(parse_command_line(argc, argv, opts), vm);

  string flavour;
  if (vm.count("gru"))	flavour = "gru";
  else if (vm.count("lstm"))	flavour = "lstm";
  else if (vm.count("rnnem"))	flavour = "rnnem";
  else if (vm.count("dglstm")) flavour = "dglstm";
  else if (vm.count("nmn")) flavour = "nmn";
  else			flavour = "rnn";

  LAYERS = vm["layers"].as<int>();
  HIDDEN_DIM = vm["hidden"].as<int>();

  bool generateSample = false;
  generateSample = vm["generate"].as<bool>();

  string fname;
  if (vm.count("parameters")) {
      fname = vm["parameters"].as<string>();
  }
  else {
      ostringstream os;
      os << "lm"
          << '_' << LAYERS
          << '_' << HIDDEN_DIM
          << '_' << flavour
          << "-pid" << getpid() << ".params";
      fname = os.str();
  }

  cerr << "Parameters will be written to: " << fname << endl;

  if (vm.count("help") || vm.count("train") != 1 || (vm.count("devel") != 1 && vm.count("test") != 1)) {
      cout << opts << "\n";
      return 1;
  }

  kSOS = d.Convert("<s>");
  kEOS = d.Convert("</s>");
  vector<vector<int>> training, dev, test;
  string line;
  int tlc = 0;
  int ttoks = 0;

  string infile = vm["train"].as<string>();
  cerr << "Reading training data from " << infile << "...\n";

  {
    ifstream in(infile);
    assert(in);
    while(getline(in, line)) {
      ++tlc;
      training.push_back(ReadSentence(line, &d));
      ttoks += training.back().size();
      if (training.back().front() != kSOS && training.back().back() != kEOS) {
        cerr << "Training sentence in " << infile << ":" << tlc << " didn't start or end with <s>, </s>\n";
        abort();
      }
    }
    cerr << tlc << " lines, " << ttoks << " tokens, " << d.size() << " types\n";
  }
  d.Freeze(); // no new word types allowed
  VOCAB_SIZE = d.size();

  if (vm.count("devel") > 0)
  {
      int dlc = 0;
      int dtoks = 0;
      string devfile = vm["devel"].as<string>();
      cerr << "Reading training data from " << devfile << "...\n";
      {
          ifstream in(devfile);
          assert(in);
          while (getline(in, line)) {
              ++dlc;
              dev.push_back(ReadSentence(line, &d));
              dtoks += dev.back().size();
              if (dev.back().front() != kSOS && dev.back().back() != kEOS) {
                  cerr << "Dev sentence in " << devfile << ":" << tlc << " didn't start or end with <s>, </s>\n";
                  abort();
              }
          }
          cerr << dlc << " lines, " << dtoks << " tokens\n";
      }
  }

  Model model;
  bool use_momentum = false;
  Trainer* sgd = nullptr;
  //if (use_momentum)
  //  sgd = new MomentumSGDTrainer(&model);
  //else
  sgd = new SimpleSGDTrainer(&model);

  if (vm.count("test") == 0)
  {
      if (vm.count("lstm")) {
          cerr << "%% Using LSTM recurrent units" << endl;
          RNNLanguageModel<LSTMBuilder> lm(model);
          train(model, lm, training, dev, sgd, fname, generateSample);
      }
      else if (vm.count("dglstm")) {
          cerr << "%% Using DGLSTM recurrent units" << endl;
          RNNLanguageModel<DGLSTMBuilder> lm(model);
          train(model, lm, training, dev, sgd, fname, generateSample);
      }
  }
  else
  {
      string testfile = vm["test"].as<string>();
      int dlc = 0;
      int dtoks = 0;
      cerr << "Reading training data from " << testfile << "...\n";
      {
          ifstream in(testfile);
          assert(in);
          while (getline(in, line)) {
              ++dlc;
              test.push_back(ReadSentence(line, &d));
              dtoks += test.back().size();
              if (test.back().front() != kSOS && test.back().back() != kEOS) {
                  cerr << "Dev sentence in " << testfile << ":" << tlc << " didn't start or end with <s>, </s>\n";
                  abort();
              }
          }
          cerr << dlc << " lines, " << dtoks << " tokens\n";
      }

      if (vm.count("test"))
      {
          if (vm.count("lstm")){
              cerr << "%% using LSTM recurrent units" << endl;
              RNNLanguageModel<LSTMBuilder> lm(model);
              if (vm.count("initialise"))
                  initialise(model, vm["initialise"].as<string>());
              testcorpus(model, lm, test);
          }
          if (vm.count("dglstm")){
              cerr << "%% using DGLSTM recurrent units" << endl;
              RNNLanguageModel<DGLSTMBuilder> lm(model);
              if (vm.count("initialise"))
                  initialise(model, vm["initialise"].as<string>());
              testcorpus(model, lm, test);
          }
      }
  }

  //RNNLanguageModel<SimpleRNNBuilder> lm(model);
  if (argc == 4) {
    string fname = argv[3];
    ifstream in(fname);
    boost::archive::text_iarchive ia(in);
    ia >> model;
  }

  delete sgd;
}

<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tab_contents/web_contents_view.h"

#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/web_contents.h"

WebContentsView::WebContentsView(WebContents* web_contents)
    : web_contents_(web_contents) {
}

void WebContentsView::RenderWidgetHostDestroyed(RenderWidgetHost* host) {
  for (PendingWidgetViews::iterator i = pending_widget_views_.begin();
       i != pending_widget_views_.end(); ++i) {
    if (host->view() == i->second) {
      pending_widget_views_.erase(i);
      return;
    }
  }
}

void WebContentsView::CreateNewWindow(int route_id,
                                      base::WaitableEvent* modal_dialog_event) {
  // Create the new web contents. This will automatically create the new
  // WebContentsView. In the future, we may want to create the view separately.
  WebContents* new_contents =
      new WebContents(web_contents()->profile(),
                      web_contents()->GetSiteInstance(),
                      route_id,
                      modal_dialog_event);
  new_contents->SetupController(web_contents()->profile());
  WebContentsView* new_view = new_contents->view();

  // TODO(brettw) it seems bogus that we have to call this function on the
  // newly created object and give it one of its own member variables.
  new_view->CreateViewForWidget(new_contents->render_view_host());

  // Save the created window associated with the route so we can show it later.
  pending_contents_[route_id] = new_contents;
}

void WebContentsView::CreateNewWidget(int route_id, bool activatable) {
  // Save the created widget associated with the route so we can show it later.
  pending_widget_views_[route_id] = CreateNewWidgetInternal(route_id,
                                                            activatable);
}

void WebContentsView::ShowCreatedWindow(int route_id,
                                        WindowOpenDisposition disposition,
                                        const gfx::Rect& initial_pos,
                                        bool user_gesture) {
  PendingContents::iterator iter = pending_contents_.find(route_id);
  if (iter == pending_contents_.end()) {
    DCHECK(false);
    return;
  }

  WebContents* new_web_contents = iter->second;
  pending_contents_.erase(route_id);

  if (!new_web_contents->render_widget_host_view() ||
      !new_web_contents->process()->channel()) {
    // The view has gone away or the renderer crashed. Nothing to do.
    return;
  }

  // TODO(brettw) this seems bogus to reach into here and initialize the host.
  new_web_contents->render_view_host()->Init();
  web_contents()->AddNewContents(new_web_contents, disposition, initial_pos,
                                 user_gesture);
}

void WebContentsView::ShowCreatedWidget(int route_id,
                                        const gfx::Rect& initial_pos) {
  PendingWidgetViews::iterator iter = pending_widget_views_.find(route_id);
  if (iter == pending_widget_views_.end()) {
    DCHECK(false);
    return;
  }

  RenderWidgetHostView* widget_host_view = iter->second;
  pending_widget_views_.erase(route_id);

  ShowCreatedWidgetInternal(widget_host_view, initial_pos);
}

RenderWidgetHostView* WebContentsView::CreateNewWidgetInternal(
    int route_id,
    bool activatable) {
  RenderWidgetHost* widget_host =
      new RenderWidgetHost(web_contents_->process(), route_id);
  RenderWidgetHostView* widget_view =
      RenderWidgetHostView::CreateViewForWidget(widget_host);
  widget_view->set_activatable(activatable);

  return widget_view;
}

void WebContentsView::ShowCreatedWidgetInternal(
    RenderWidgetHostView* widget_host_view,
    const gfx::Rect& initial_pos) {
  RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost();
  if (!widget_host->process()->channel()) {
    // The view has gone away or the renderer crashed. Nothing to do.
    return;
  }

  widget_host_view->InitAsPopup(
      web_contents_->render_widget_host_view(), initial_pos);
  if (web_contents_->delegate())
    web_contents_->delegate()->RenderWidgetShowing();
  widget_host->Init();
}
<commit_msg>Disable inactive rendering for the frame before select popups are initialized, since initializing shows them which causes activation to change.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/tab_contents/web_contents_view.h"

#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_widget_host.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/tab_contents/tab_contents_delegate.h"
#include "chrome/browser/tab_contents/web_contents.h"

WebContentsView::WebContentsView(WebContents* web_contents)
    : web_contents_(web_contents) {
}

void WebContentsView::RenderWidgetHostDestroyed(RenderWidgetHost* host) {
  for (PendingWidgetViews::iterator i = pending_widget_views_.begin();
       i != pending_widget_views_.end(); ++i) {
    if (host->view() == i->second) {
      pending_widget_views_.erase(i);
      return;
    }
  }
}

void WebContentsView::CreateNewWindow(int route_id,
                                      base::WaitableEvent* modal_dialog_event) {
  // Create the new web contents. This will automatically create the new
  // WebContentsView. In the future, we may want to create the view separately.
  WebContents* new_contents =
      new WebContents(web_contents()->profile(),
                      web_contents()->GetSiteInstance(),
                      route_id,
                      modal_dialog_event);
  new_contents->SetupController(web_contents()->profile());
  WebContentsView* new_view = new_contents->view();

  // TODO(brettw) it seems bogus that we have to call this function on the
  // newly created object and give it one of its own member variables.
  new_view->CreateViewForWidget(new_contents->render_view_host());

  // Save the created window associated with the route so we can show it later.
  pending_contents_[route_id] = new_contents;
}

void WebContentsView::CreateNewWidget(int route_id, bool activatable) {
  // Save the created widget associated with the route so we can show it later.
  pending_widget_views_[route_id] = CreateNewWidgetInternal(route_id,
                                                            activatable);
}

void WebContentsView::ShowCreatedWindow(int route_id,
                                        WindowOpenDisposition disposition,
                                        const gfx::Rect& initial_pos,
                                        bool user_gesture) {
  PendingContents::iterator iter = pending_contents_.find(route_id);
  if (iter == pending_contents_.end()) {
    DCHECK(false);
    return;
  }

  WebContents* new_web_contents = iter->second;
  pending_contents_.erase(route_id);

  if (!new_web_contents->render_widget_host_view() ||
      !new_web_contents->process()->channel()) {
    // The view has gone away or the renderer crashed. Nothing to do.
    return;
  }

  // TODO(brettw) this seems bogus to reach into here and initialize the host.
  new_web_contents->render_view_host()->Init();
  web_contents()->AddNewContents(new_web_contents, disposition, initial_pos,
                                 user_gesture);
}

void WebContentsView::ShowCreatedWidget(int route_id,
                                        const gfx::Rect& initial_pos) {
  PendingWidgetViews::iterator iter = pending_widget_views_.find(route_id);
  if (iter == pending_widget_views_.end()) {
    DCHECK(false);
    return;
  }

  RenderWidgetHostView* widget_host_view = iter->second;
  pending_widget_views_.erase(route_id);

  ShowCreatedWidgetInternal(widget_host_view, initial_pos);
}

RenderWidgetHostView* WebContentsView::CreateNewWidgetInternal(
    int route_id,
    bool activatable) {
  RenderWidgetHost* widget_host =
      new RenderWidgetHost(web_contents_->process(), route_id);
  RenderWidgetHostView* widget_view =
      RenderWidgetHostView::CreateViewForWidget(widget_host);
  widget_view->set_activatable(activatable);

  return widget_view;
}

void WebContentsView::ShowCreatedWidgetInternal(
    RenderWidgetHostView* widget_host_view,
    const gfx::Rect& initial_pos) {
  RenderWidgetHost* widget_host = widget_host_view->GetRenderWidgetHost();
  if (!widget_host->process()->channel()) {
    // The view has gone away or the renderer crashed. Nothing to do.
    return;
  }

  if (web_contents_->delegate())
    web_contents_->delegate()->RenderWidgetShowing();
  widget_host_view->InitAsPopup(
      web_contents_->render_widget_host_view(), initial_pos);
  widget_host->Init();
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_FUN_CORR_MATRIX_CONSTRAIN_HPP
#define STAN_MATH_PRIM_MAT_FUN_CORR_MATRIX_CONSTRAIN_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/meta/index_type.hpp>
#include <stan/math/prim/scal/err/check_size_match.hpp>
#include <stan/math/prim/scal/fun/corr_constrain.hpp>
#include <stan/math/prim/mat/fun/read_corr_matrix.hpp>
#include <stdexcept>

namespace stan {
namespace math {

/**
 * Return the correlation matrix of the specified dimensionality
 * derived from the specified vector of unconstrained values.  The
 * input vector must be of length \f${k \choose 2} =
 * \frac{k(k-1)}{2}\f$.  The values in the input vector represent
 * unconstrained (partial) correlations among the dimensions.
 *
 *
The transform based on partial correlations is as specified
 * in
 *
 *

 Lewandowski, Daniel, Dorota Kurowicka, and Harry
 * Joe. 2009.  Generating random correlation matrices based on
 * vines and extended onion method.  Journal of Multivariate
 * Analysis 100:1989–-2001.

 *
 *
The free vector entries are first constrained to be
 * valid correlation values using corr_constrain(T).
 *
 * @param x Vector of unconstrained partial correlations.
 * @param k Dimensionality of returned correlation matrix.
 * @tparam T Type of scalar.
 * @throw std::invalid_argument if x is not a valid correlation
 * matrix.
 */
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> corr_matrix_constrain(
    const Eigen::Matrix<T, Eigen::Dynamic, 1>& x,
    typename math::index_type<Eigen::Matrix<T, Eigen::Dynamic, 1> >::type k) {
  using Eigen::Dynamic;
  using Eigen::Matrix;
  typedef typename index_type<Matrix<T, Dynamic, 1> >::type size_type;

  size_type k_choose_2 = (k * (k - 1)) / 2;
  check_size_match("cov_matrix_constrain", "x.size()", x.size(), "k_choose_2",
                   k_choose_2);
  Eigen::Array<T, Eigen::Dynamic, 1> cpcs(k_choose_2);
  for (size_type i = 0; i < k_choose_2; ++i)
    cpcs[i] = corr_constrain(x[i]);
  return read_corr_matrix(cpcs, k);
}

/**
 * Return the correlation matrix of the specified dimensionality
 * derived from the specified vector of unconstrained values.  The
 * input vector must be of length \f${k \choose 2} =
 * \frac{k(k-1)}{2}\f$.  The values in the input vector represent
 * unconstrained (partial) correlations among the dimensions.
 *
 *
The transform is as specified for
 * corr_matrix_constrain(Matrix, size_t); the
 * paper it cites also defines the Jacobians for correlation inputs,
 * which are composed with the correlation constrained Jacobians
 * defined in corr_constrain(T, double) for
 * this function.
 *
 * @param x Vector of unconstrained partial correlations.
 * @param k Dimensionality of returned correlation matrix.
 * @param lp Log probability reference to increment.
 * @tparam T Type of scalar.
 */
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> corr_matrix_constrain(
    const Eigen::Matrix<T, Eigen::Dynamic, 1>& x,
    typename math::index_type<Eigen::Matrix<T, Eigen::Dynamic, 1> >::type k,
    T& lp) {
  using Eigen::Array;
  using Eigen::Dynamic;
  using Eigen::Matrix;
  typedef typename index_type<Matrix<T, Dynamic, 1> >::type size_type;

  size_type k_choose_2 = (k * (k - 1)) / 2;
  check_size_match("cov_matrix_constrain", "x.size()", x.size(), "k_choose_2",
                   k_choose_2);
  Array<T, Dynamic, 1> cpcs(k_choose_2);
  for (size_type i = 0; i < k_choose_2; ++i)
    cpcs[i] = corr_constrain(x[i], lp);
  return read_corr_matrix(cpcs, k, lp);
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>include meta.hpp<commit_after>#ifndef STAN_MATH_PRIM_MAT_FUN_CORR_MATRIX_CONSTRAIN_HPP
#define STAN_MATH_PRIM_MAT_FUN_CORR_MATRIX_CONSTRAIN_HPP

#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/scal/err/check_size_match.hpp>
#include <stan/math/prim/scal/fun/corr_constrain.hpp>
#include <stan/math/prim/mat/fun/read_corr_matrix.hpp>
#include <stdexcept>

namespace stan {
namespace math {

/**
 * Return the correlation matrix of the specified dimensionality
 * derived from the specified vector of unconstrained values.  The
 * input vector must be of length \f${k \choose 2} =
 * \frac{k(k-1)}{2}\f$.  The values in the input vector represent
 * unconstrained (partial) correlations among the dimensions.
 *
 *
The transform based on partial correlations is as specified
 * in
 *
 *

 Lewandowski, Daniel, Dorota Kurowicka, and Harry
 * Joe. 2009.  Generating random correlation matrices based on
 * vines and extended onion method.  Journal of Multivariate
 * Analysis 100:1989–-2001.

 *
 *
The free vector entries are first constrained to be
 * valid correlation values using corr_constrain(T).
 *
 * @param x Vector of unconstrained partial correlations.
 * @param k Dimensionality of returned correlation matrix.
 * @tparam T Type of scalar.
 * @throw std::invalid_argument if x is not a valid correlation
 * matrix.
 */
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> corr_matrix_constrain(
    const Eigen::Matrix<T, Eigen::Dynamic, 1>& x,
    typename math::index_type<Eigen::Matrix<T, Eigen::Dynamic, 1> >::type k) {
  using Eigen::Dynamic;
  using Eigen::Matrix;
  typedef typename index_type<Matrix<T, Dynamic, 1> >::type size_type;

  size_type k_choose_2 = (k * (k - 1)) / 2;
  check_size_match("cov_matrix_constrain", "x.size()", x.size(), "k_choose_2",
                   k_choose_2);
  Eigen::Array<T, Eigen::Dynamic, 1> cpcs(k_choose_2);
  for (size_type i = 0; i < k_choose_2; ++i)
    cpcs[i] = corr_constrain(x[i]);
  return read_corr_matrix(cpcs, k);
}

/**
 * Return the correlation matrix of the specified dimensionality
 * derived from the specified vector of unconstrained values.  The
 * input vector must be of length \f${k \choose 2} =
 * \frac{k(k-1)}{2}\f$.  The values in the input vector represent
 * unconstrained (partial) correlations among the dimensions.
 *
 *
The transform is as specified for
 * corr_matrix_constrain(Matrix, size_t); the
 * paper it cites also defines the Jacobians for correlation inputs,
 * which are composed with the correlation constrained Jacobians
 * defined in corr_constrain(T, double) for
 * this function.
 *
 * @param x Vector of unconstrained partial correlations.
 * @param k Dimensionality of returned correlation matrix.
 * @param lp Log probability reference to increment.
 * @tparam T Type of scalar.
 */
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> corr_matrix_constrain(
    const Eigen::Matrix<T, Eigen::Dynamic, 1>& x,
    typename math::index_type<Eigen::Matrix<T, Eigen::Dynamic, 1> >::type k,
    T& lp) {
  using Eigen::Array;
  using Eigen::Dynamic;
  using Eigen::Matrix;
  typedef typename index_type<Matrix<T, Dynamic, 1> >::type size_type;

  size_type k_choose_2 = (k * (k - 1)) / 2;
  check_size_match("cov_matrix_constrain", "x.size()", x.size(), "k_choose_2",
                   k_choose_2);
  Array<T, Dynamic, 1> cpcs(k_choose_2);
  for (size_type i = 0; i < k_choose_2; ++i)
    cpcs[i] = corr_constrain(x[i], lp);
  return read_corr_matrix(cpcs, k, lp);
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "contextc.h"
#include "service.h"
#include "property.h"
#include "group.h"
#include "logging.h"
#include "sconnect.h"
#include "listeners.h"
#include "loggingfeatures.h"

#include <QCoreApplication>

namespace ContextProvider {
}

using namespace ContextProvider;

/*!
    \page CApi C Api

    \brief The libcontextprovider library offers a simple plain-C API to be used
    from any C program.

    \section Usage

    \code
    context_provider_init(DBUS_BUS_SESSION, "org.test.provider");

    context_provider_install_key("Battery.OnBattery", 0, NULL, NULL);
    context_provider_install_key("Battery.ChargePercentage", 0, NULL, NULL);

    context_provider_set_boolean("Battery.OnBattery", 1);
    context_provider_set_integer("Battery.ChargePercentage", 55);
    \endcode

    The above code snippet starts a service at "org.test.provider" with two
    keys ("Battery.OnBattery", "Battery.ChargePercentage") and sets their
    respective values.

    Note: If the provider used other D-Bus bindings than QDBus, the
    service name ("org.test.provider") needs to be unique, i.e., the
    provider process should not register it itself.

    \section Callbacks

    The context_provider_install_key function and context_provider_install_group function
    take arguments specyfying the callback function. The callback is executed when the
    subscription status changes for the key or the key group (first subscriber
    appears or last subscriber goes away). Basing on this info the provider can
    manage it's resources. It's okay also to use the callback function to actually
    set the value.

    \code
    void callback_function_example(int subscribed, void* user_data)
    {
        if (subscribed) {
            // First subscriber appeared.
            // Start ie. pooling the data.
        } else {
            // Last subscribed disappeared.
            // Stop  pooling data, release resources.
        }
    }
    \endcode
*/

static Service *cService;
static QList<Listener*> *listeners = NULL;

/// Initializes and starts the service with a given \a bus_type and a \a bus_name.
/// The \a bus_type can be DBUS_BUS_SESSION or DBUS_BUS_SYSTEM. This function can be
/// called only once till a matching context_provider_stop is called.
int context_provider_init (DBusBusType bus_type, const char* bus_name)
{
    contextDebug() << F_C << bus_name;

    static char arg[] = "libcontextprovider";
    static char* p = arg;
    static int argc = 1;
    static QCoreApplication* app = 0;

    if (QCoreApplication::instance() == 0) {
        // No QCoreApplication created, so crate one.
        // This will also create an event dispatcher (QEventDispatcherGlibPrivate.)
        app = new QCoreApplication(argc, &p);
    }

    if (cService != NULL) {
        contextCritical() << "Service already initialized. You can only initialize one service with C API";
        return 0;
    }

    cService = new Service(bus_type == DBUS_BUS_SESSION
                           ? QDBusConnection::SessionBus
                           : QDBusConnection::SystemBus,
                           bus_name);
    listeners = new QList<Listener*>;

    return 1;
}

/// Stops the currently started service with context_provider_init. After calling
/// this function a new service can be started by calling context_provider_init.
void context_provider_stop (void)
{
    contextDebug() << F_C;
    if (cService) {
        contextDebug() << "Stopping service";

        // Delete all listeners
        if (listeners) {
            Q_FOREACH (Listener *listener, *listeners)
                delete listener;
        }
        delete listeners; listeners = NULL;

        delete cService;
        cService = NULL;
    }
    // We cannot destroy the QCoreApplication we might have created; it must
    // be kept alive in case the provider calls init again.
}

/// Installs (adds) a \a key to be provided by the service. The callback function \a
/// subscription_changed_cb will be called with the passed user data \a subscription_changed_cb_target
/// when the status of the subscription changes -- when the first subscriber appears or the
/// last subscriber disappears. The \a clear_values_on_subscribe when enabled will automatically
/// clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_key (const char* key,
                                   int clear_values_on_subscribe,
                                   ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                   void* subscription_changed_cb_target)
{
    contextDebug() << F_C << key;

    if (! cService) {
        contextCritical() << "Can't install key:" << key << "because no service started.";
        return;
    }

    listeners->append(new PropertyListener(*cService, key,
                                           clear_values_on_subscribe,
                                           subscription_changed_cb, subscription_changed_cb_target));
    cService->restart();
}

/// Installs (adds) a \a key_group to be provided by the service. The \a key_group is a NULL-terminated
/// array containing the keys. The callback function \a subscription_changed_cb will be called with the
/// passed user data \a subscription_changed_cb_target when the status of the subscription changes --
/// when the first subscriber appears or the last subscriber disappears. The \a clear_values_on_subscribe
/// when enabled will automatically clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_group (char* const * key_group,
                                     int clear_values_on_subscribe,
                                     ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                     void* subscription_changed_cb_target)
{
    contextDebug() << F_C;

    if (! cService) {
        contextCritical() << "Can't install key group because no service started.";
        return;
    }

    QStringList keys;
    int i = 0;
    while(key_group[i] != NULL) {
        QString key = QString(key_group[i]);

        keys << key;
        i++;
    }

    listeners->append(new GroupListener(*cService, keys,
                                        clear_values_on_subscribe,
                                        subscription_changed_cb, subscription_changed_cb_target));
    cService->restart();
}

/// Sets the \a key to a specified integer \a value.
void context_provider_set_integer (const char* key, int value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, value);
}

/// Sets the \a key to a specified double \a value.
void context_provider_set_double (const char* key, double value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, value);
}

/// Sets the \a key to a specified boolean \a value.
void context_provider_set_boolean (const char* key, int value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, (value != 0));
}

/// Sets the \a key to a specified string \a value. \a value should be UTF-8.
void context_provider_set_string (const char* key, const char* value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, QString::fromUtf8(value));
}

/// Sets the \a key to NULL. In other words - unsets the key.
void context_provider_set_null (const char* key)
{
    contextDebug() << F_C << key;
    if (cService)
        cService->setValue(key, QVariant());
}

/// Sets the value of \a key to the specified \a map.  If \a free_map is TRUE,
/// frees the map, which becomes invalid afterwards.
///
/// \sa context_provider_map_new, context_provider_map_set_*
void context_provider_set_map (const char* key, void* map, int free_map)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    cService->setValue(key, QVariant(*qvm));
    if (free_map)
        delete qvm;
}

/// Creates an opaque map for use with the context_provider_map_set_* family
/// of functions.  Free it with context_provider_map_free().
void *context_provider_map_new ()
{
    return new QVariantMap();
}

/// Free the \a map created by context_provider_map_new().
void context_provider_map_free (void* map)
{
    delete reinterpret_cast<QVariantMap *>(map);
}

/// Sets \a key to the integer \a value in \a map.
void context_provider_map_set_integer(void* map, const char* key, int value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the double \a value in \a map.
void context_provider_map_set_double (void* map, const char* key, double value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the boolean \a value in \a map.
void context_provider_map_set_boolean(void* map, const char* key, int value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value != 0));
}

/// Sets \a key to the string \a value in \a map.
void context_provider_map_set_string (void* map, const char* key, const char* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the map \a value in \a map.  NOTE: \a value is freed, and
/// becomes invalid after this call.
void context_provider_map_set_map (void* map, const char* key, void* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    QVariantMap *other = reinterpret_cast<QVariantMap *>(value);
    qvm->insert(key, QVariant(*other));
    delete other;
}

/// Sets \a key to the list \a value in \a map.  NOTE: \a value is freed, and
/// becomes invalid after this call.
void context_provider_map_set_list(void* map, const char* key, void* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    QVariantList *list = reinterpret_cast<QVariantList *>(value);
    qvm->insert(key, QVariant(*list));
    delete list;
}

/// Sets the value of \a key to the specified \a list.  If \a free_list is
/// TRUE, the list is freed.
///
/// \sa context_provider_list_new, context_provider_list_add_*
void context_provider_set_list(const char* key, void* list, int free_list)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    cService->setValue(key, QVariant(*qvl));
    if (free_list)
        delete qvl;
}

/// Creates an opaque list for use with the context_provider_list_add_* family
/// of functions.  Free it with context_provider_list_free().
void *context_provider_list_new()
{
    return new QVariantList();
}

/// Frees the list created by context_provider_list_new().  Use
/// context_provider_list_free() to free it.
void context_provider_list_free(void* list)
{
    delete reinterpret_cast<QVariantList *>(list);
}

/// Appends the integer \a value to \a list.
void context_provider_list_add_integer(void* list, int value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the double \a value to \a list.
void context_provider_list_add_double(void* list, double value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the boolean \a value to \a list.
void context_provider_list_add_boolean(void* list, int value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value != 0));
}

/// Appends the string \a value to \a list.
void context_provider_list_add_string(void* list, const char* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the specified map (\a value) to \a list.  NOTE: \a value is freed
/// and becomes invalid after this call.
void context_provider_list_add_map(void* list, void* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(value);
    qvl->append(QVariant(*qvm));
    delete qvm;
}

/// Appends the specified list \a value to \a list.  NOTE: \a value is freed,
/// and becomes invalid after this call.
void context_provider_list_add_list(void* list, void* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    QVariantList *vl = reinterpret_cast<QVariantList *>(value);
    qvl->append(QVariant(*vl));
    delete vl;
}
<commit_msg>context_provider_map_set_string, _add_string: the same UTF-8 fix.<commit_after>/*
 * Copyright (C) 2008 Nokia Corporation.
 *
 * Contact: Marius Vollmer <marius.vollmer@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#include "contextc.h"
#include "service.h"
#include "property.h"
#include "group.h"
#include "logging.h"
#include "sconnect.h"
#include "listeners.h"
#include "loggingfeatures.h"

#include <QCoreApplication>

namespace ContextProvider {
}

using namespace ContextProvider;

/*!
    \page CApi C Api

    \brief The libcontextprovider library offers a simple plain-C API to be used
    from any C program.

    \section Usage

    \code
    context_provider_init(DBUS_BUS_SESSION, "org.test.provider");

    context_provider_install_key("Battery.OnBattery", 0, NULL, NULL);
    context_provider_install_key("Battery.ChargePercentage", 0, NULL, NULL);

    context_provider_set_boolean("Battery.OnBattery", 1);
    context_provider_set_integer("Battery.ChargePercentage", 55);
    \endcode

    The above code snippet starts a service at "org.test.provider" with two
    keys ("Battery.OnBattery", "Battery.ChargePercentage") and sets their
    respective values.

    Note: If the provider used other D-Bus bindings than QDBus, the
    service name ("org.test.provider") needs to be unique, i.e., the
    provider process should not register it itself.

    \section Callbacks

    The context_provider_install_key function and context_provider_install_group function
    take arguments specyfying the callback function. The callback is executed when the
    subscription status changes for the key or the key group (first subscriber
    appears or last subscriber goes away). Basing on this info the provider can
    manage it's resources. It's okay also to use the callback function to actually
    set the value.

    \code
    void callback_function_example(int subscribed, void* user_data)
    {
        if (subscribed) {
            // First subscriber appeared.
            // Start ie. pooling the data.
        } else {
            // Last subscribed disappeared.
            // Stop  pooling data, release resources.
        }
    }
    \endcode
*/

static Service *cService;
static QList<Listener*> *listeners = NULL;

/// Initializes and starts the service with a given \a bus_type and a \a bus_name.
/// The \a bus_type can be DBUS_BUS_SESSION or DBUS_BUS_SYSTEM. This function can be
/// called only once till a matching context_provider_stop is called.
int context_provider_init (DBusBusType bus_type, const char* bus_name)
{
    contextDebug() << F_C << bus_name;

    static char arg[] = "libcontextprovider";
    static char* p = arg;
    static int argc = 1;
    static QCoreApplication* app = 0;

    if (QCoreApplication::instance() == 0) {
        // No QCoreApplication created, so crate one.
        // This will also create an event dispatcher (QEventDispatcherGlibPrivate.)
        app = new QCoreApplication(argc, &p);
    }

    if (cService != NULL) {
        contextCritical() << "Service already initialized. You can only initialize one service with C API";
        return 0;
    }

    cService = new Service(bus_type == DBUS_BUS_SESSION
                           ? QDBusConnection::SessionBus
                           : QDBusConnection::SystemBus,
                           bus_name);
    listeners = new QList<Listener*>;

    return 1;
}

/// Stops the currently started service with context_provider_init. After calling
/// this function a new service can be started by calling context_provider_init.
void context_provider_stop (void)
{
    contextDebug() << F_C;
    if (cService) {
        contextDebug() << "Stopping service";

        // Delete all listeners
        if (listeners) {
            Q_FOREACH (Listener *listener, *listeners)
                delete listener;
        }
        delete listeners; listeners = NULL;

        delete cService;
        cService = NULL;
    }
    // We cannot destroy the QCoreApplication we might have created; it must
    // be kept alive in case the provider calls init again.
}

/// Installs (adds) a \a key to be provided by the service. The callback function \a
/// subscription_changed_cb will be called with the passed user data \a subscription_changed_cb_target
/// when the status of the subscription changes -- when the first subscriber appears or the
/// last subscriber disappears. The \a clear_values_on_subscribe when enabled will automatically
/// clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_key (const char* key,
                                   int clear_values_on_subscribe,
                                   ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                   void* subscription_changed_cb_target)
{
    contextDebug() << F_C << key;

    if (! cService) {
        contextCritical() << "Can't install key:" << key << "because no service started.";
        return;
    }

    listeners->append(new PropertyListener(*cService, key,
                                           clear_values_on_subscribe,
                                           subscription_changed_cb, subscription_changed_cb_target));
    cService->restart();
}

/// Installs (adds) a \a key_group to be provided by the service. The \a key_group is a NULL-terminated
/// array containing the keys. The callback function \a subscription_changed_cb will be called with the
/// passed user data \a subscription_changed_cb_target when the status of the subscription changes --
/// when the first subscriber appears or the last subscriber disappears. The \a clear_values_on_subscribe
/// when enabled will automatically clear (set to null/undetermined) the group keys on first subscribe.
void context_provider_install_group (char* const * key_group,
                                     int clear_values_on_subscribe,
                                     ContextProviderSubscriptionChangedCallback subscription_changed_cb,
                                     void* subscription_changed_cb_target)
{
    contextDebug() << F_C;

    if (! cService) {
        contextCritical() << "Can't install key group because no service started.";
        return;
    }

    QStringList keys;
    int i = 0;
    while(key_group[i] != NULL) {
        QString key = QString(key_group[i]);

        keys << key;
        i++;
    }

    listeners->append(new GroupListener(*cService, keys,
                                        clear_values_on_subscribe,
                                        subscription_changed_cb, subscription_changed_cb_target));
    cService->restart();
}

/// Sets the \a key to a specified integer \a value.
void context_provider_set_integer (const char* key, int value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, value);
}

/// Sets the \a key to a specified double \a value.
void context_provider_set_double (const char* key, double value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, value);
}

/// Sets the \a key to a specified boolean \a value.
void context_provider_set_boolean (const char* key, int value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, (value != 0));
}

/// Sets the \a key to a specified string \a value. \a value should be UTF-8.
void context_provider_set_string (const char* key, const char* value)
{
    contextDebug() << F_C << key << value;
    if (cService)
        cService->setValue(key, QString::fromUtf8(value));
}

/// Sets the \a key to NULL. In other words - unsets the key.
void context_provider_set_null (const char* key)
{
    contextDebug() << F_C << key;
    if (cService)
        cService->setValue(key, QVariant());
}

/// Sets the value of \a key to the specified \a map.  If \a free_map is TRUE,
/// frees the map, which becomes invalid afterwards.
///
/// \sa context_provider_map_new, context_provider_map_set_*
void context_provider_set_map (const char* key, void* map, int free_map)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    cService->setValue(key, QVariant(*qvm));
    if (free_map)
        delete qvm;
}

/// Creates an opaque map for use with the context_provider_map_set_* family
/// of functions.  Free it with context_provider_map_free().
void *context_provider_map_new ()
{
    return new QVariantMap();
}

/// Free the \a map created by context_provider_map_new().
void context_provider_map_free (void* map)
{
    delete reinterpret_cast<QVariantMap *>(map);
}

/// Sets \a key to the integer \a value in \a map.
void context_provider_map_set_integer(void* map, const char* key, int value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the double \a value in \a map.
void context_provider_map_set_double (void* map, const char* key, double value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value));
}

/// Sets \a key to the boolean \a value in \a map.
void context_provider_map_set_boolean(void* map, const char* key, int value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(value != 0));
}

/// Sets \a key to the string \a value in \a map.
void context_provider_map_set_string (void* map, const char* key, const char* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    qvm->insert(key, QVariant(QString::fromUtf8(value)));
}

/// Sets \a key to the map \a value in \a map.  NOTE: \a value is freed, and
/// becomes invalid after this call.
void context_provider_map_set_map (void* map, const char* key, void* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    QVariantMap *other = reinterpret_cast<QVariantMap *>(value);
    qvm->insert(key, QVariant(*other));
    delete other;
}

/// Sets \a key to the list \a value in \a map.  NOTE: \a value is freed, and
/// becomes invalid after this call.
void context_provider_map_set_list(void* map, const char* key, void* value)
{
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(map);
    QVariantList *list = reinterpret_cast<QVariantList *>(value);
    qvm->insert(key, QVariant(*list));
    delete list;
}

/// Sets the value of \a key to the specified \a list.  If \a free_list is
/// TRUE, the list is freed.
///
/// \sa context_provider_list_new, context_provider_list_add_*
void context_provider_set_list(const char* key, void* list, int free_list)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    cService->setValue(key, QVariant(*qvl));
    if (free_list)
        delete qvl;
}

/// Creates an opaque list for use with the context_provider_list_add_* family
/// of functions.  Free it with context_provider_list_free().
void *context_provider_list_new()
{
    return new QVariantList();
}

/// Frees the list created by context_provider_list_new().  Use
/// context_provider_list_free() to free it.
void context_provider_list_free(void* list)
{
    delete reinterpret_cast<QVariantList *>(list);
}

/// Appends the integer \a value to \a list.
void context_provider_list_add_integer(void* list, int value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the double \a value to \a list.
void context_provider_list_add_double(void* list, double value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value));
}

/// Appends the boolean \a value to \a list.
void context_provider_list_add_boolean(void* list, int value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(value != 0));
}

/// Appends the string \a value to \a list.
void context_provider_list_add_string(void* list, const char* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    qvl->append(QVariant(QString::fromUtf8(value)));
}

/// Appends the specified map (\a value) to \a list.  NOTE: \a value is freed
/// and becomes invalid after this call.
void context_provider_list_add_map(void* list, void* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    QVariantMap *qvm = reinterpret_cast<QVariantMap *>(value);
    qvl->append(QVariant(*qvm));
    delete qvm;
}

/// Appends the specified list \a value to \a list.  NOTE: \a value is freed,
/// and becomes invalid after this call.
void context_provider_list_add_list(void* list, void* value)
{
    QVariantList *qvl = reinterpret_cast<QVariantList *>(list);
    QVariantList *vl = reinterpret_cast<QVariantList *>(value);
    qvl->append(QVariant(*vl));
    delete vl;
}
<|endoftext|>