<commit_before>// $Id$

/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2006 University of Edinburgh

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/

#include <cstring>
#include <iostream>
#include <memory>
#include <stdlib.h>
#include "lm/binary_format.hh"
#include "lm/enumerate_vocab.hh"
#include "lm/left.hh"
#include "lm/model.hh"

#include "LM/Ken.h"
#include "LM/Base.h"
#include "FFState.h"
#include "TypeDef.h"
#include "Util.h"
#include "FactorCollection.h"
#include "Phrase.h"
#include "InputFileStream.h"
#include "StaticData.h"
#include "ChartHypothesis.h"

#include <boost/shared_ptr.hpp>

using namespace std;

namespace Moses {
namespace {

struct KenLMState : public FFState {
  lm::ngram::State state;
  int Compare(const FFState &o) const {
    const KenLMState &other = static_cast<const KenLMState &>(o);
    if (state.length < other.state.length) return -1;
    if (state.length > other.state.length) return 1;
    return std::memcmp(state.words, other.state.words, sizeof(lm::WordIndex) * state.length);
  }
};

/*
 * An implementation of single factor LM using Ken's code.
 */
template <class Model> class LanguageModelKen : public LanguageModel {
  public:
    LanguageModelKen(const std::string &file, ScoreIndexManager &manager, FactorType factorType, bool lazy);

    LanguageModel *Duplicate(ScoreIndexManager &scoreIndexManager) const;

    bool Useable(const Phrase &phrase) const {
      return (phrase.GetSize()>0 && phrase.GetFactor(0, m_factorType) != NULL);
    }

    std::string GetScoreProducerDescription(unsigned) const {
      std::ostringstream oss;
      oss << "LM_" << (unsigned)m_ngram->Order() << "gram";
      return oss.str();
    }

    const FFState *EmptyHypothesisState(const InputType &/*input*/) const {
      KenLMState *ret = new KenLMState();
      ret->state = m_ngram->BeginSentenceState();
      return ret;
    }

    void CalcScore(const Phrase &phrase, float &fullScore, float &ngramScore, size_t &oovCount) const;

    FFState *Evaluate(const Hypothesis &hypo, const FFState *ps, ScoreComponentCollection *out) const;

    FFState *EvaluateChart(const ChartHypothesis& cur_hypo, int featureID, ScoreComponentCollection *accumulator) const;

  private:
    LanguageModelKen(ScoreIndexManager &manager, const LanguageModelKen<Model> &copy_from);

    lm::WordIndex TranslateID(const Word &word) const {
      std::size_t factor = word.GetFactor(m_factorType)->GetId();
      return (factor >= m_lmIdLookup.size() ? 0 : m_lmIdLookup[factor]);
    }

    // Convert last words of hypothesis into vocab ids, returning an end pointer.
    lm::WordIndex *LastIDs(const Hypothesis &hypo, lm::WordIndex *indices) const {
      lm::WordIndex *index = indices;
      lm::WordIndex *end = indices + m_ngram->Order() - 1;
      int position = hypo.GetCurrTargetWordsRange().GetEndPos();
      for (; ; ++index, --position) {
        if (index == end) return index;
        if (position == -1) {
          *index = m_ngram->GetVocabulary().BeginSentence();
          return index + 1;
        }
        *index = TranslateID(hypo.GetWord(position));
      }
    }

    boost::shared_ptr<Model> m_ngram;

    std::vector<lm::WordIndex> m_lmIdLookup;

    FactorType m_factorType;

    const Factor *m_beginSentenceFactor;
};

class MappingBuilder : public lm::EnumerateVocab {
public:
  MappingBuilder(FactorCollection &factorCollection, std::vector<lm::WordIndex> &mapping)
    : m_factorCollection(factorCollection), m_mapping(mapping) {}

  void Add(lm::WordIndex index, const StringPiece &str) {
    std::size_t factorId = m_factorCollection.AddFactor(str)->GetId();
    if (m_mapping.size() <= factorId) {
      // 0 is <unk> :-)
      m_mapping.resize(factorId + 1);
    }
    m_mapping[factorId] = index;
  }

private:
  FactorCollection &m_factorCollection;
  std::vector<lm::WordIndex> &m_mapping;
};

template <class Model> LanguageModelKen<Model>::LanguageModelKen(const std::string &file, ScoreIndexManager &manager, FactorType factorType, bool lazy) : m_factorType(factorType) {
  lm::ngram::Config config;
  IFVERBOSE(1) {
    config.messages = &std::cerr;
  } else {
    config.messages = NULL;
  }
  FactorCollection &collection = FactorCollection::Instance();
  MappingBuilder builder(collection, m_lmIdLookup);
  config.enumerate_vocab = &builder;
  config.load_method = lazy ? util::LAZY : util::POPULATE_OR_READ;

  m_ngram.reset(new Model(file.c_str(), config));

  m_beginSentenceFactor = collection.AddFactor(BOS_);
  Init(manager);
}

template <class Model> LanguageModel *LanguageModelKen<Model>::Duplicate(ScoreIndexManager &manager) const {
  return new LanguageModelKen<Model>(manager, *this);
}

template <class Model> LanguageModelKen<Model>::LanguageModelKen(ScoreIndexManager &manager, const LanguageModelKen<Model> &copy_from) :
    m_ngram(copy_from.m_ngram),
    // TODO: don't copy this.
    m_lmIdLookup(copy_from.m_lmIdLookup),
    m_factorType(copy_from.m_factorType),
    m_beginSentenceFactor(copy_from.m_beginSentenceFactor) {
  Init(manager);
}

template <class Model> void LanguageModelKen<Model>::CalcScore(const Phrase &phrase, float &fullScore, float &ngramScore, size_t &oovCount) const {
  fullScore = 0;
  ngramScore = 0;
  oovCount = 0;

  if (!phrase.GetSize()) return;

  typename Model::State state_backing[2];
  typename Model::State *state0 = &state_backing[0], *state1 = &state_backing[1];
  size_t position;
  if (m_beginSentenceFactor == phrase.GetWord(0).GetFactor(m_factorType)) {
    *state0 = m_ngram->BeginSentenceState();
    position = 1;
  } else {
    *state0 = m_ngram->NullContextState();
    position = 0;
  }

  size_t ngramBoundary = m_ngram->Order() - 1;

  for (; position < phrase.GetSize(); ++position) {
    const Word &word = phrase.GetWord(position);
    if (word.IsNonTerminal()) {
      // If there's a non-terminal at 1 and we have a 5-gram LM, then positions 2 3 4 and 5 will be incomplete while position 6 is complete.
      ngramBoundary = m_ngram->Order() + position;
      *state0 = m_ngram->NullContextState();
    } else {
      lm::WordIndex index = TranslateID(word);
      if (index == m_ngram->GetVocabulary().BeginSentence()) {
        std::cerr << "Either your data contains <s> in a position other than the first word or your language model is missing <s>.  Did you build your ARPA using IRSTLM and forget to run add-start-end.sh?" << std::endl;
        abort();
      }
      float score = TransformLMScore(m_ngram->Score(*state0, index, *state1));
      std::swap(state0, state1);
      if (position >= ngramBoundary) ngramScore += score;
      fullScore += score;
      if (!index) ++oovCount;
    }
  }
}

template <class Model> FFState *LanguageModelKen<Model>::Evaluate(const Hypothesis &hypo, const FFState *ps, ScoreComponentCollection *out) const {
  const lm::ngram::State &in_state = static_cast<const KenLMState&>(*ps).state;

  std::auto_ptr<KenLMState> ret(new KenLMState());

  if (!hypo.GetCurrTargetLength()) {
    ret->state = in_state;
    return ret.release();
  }

  const std::size_t begin = hypo.GetCurrTargetWordsRange().GetStartPos();
  //[begin, end) in STL-like fashion.
  const std::size_t end = hypo.GetCurrTargetWordsRange().GetEndPos() + 1;
  const std::size_t adjust_end = std::min(end, begin + m_ngram->Order() - 1);

  std::size_t position = begin;
  typename Model::State aux_state;
  typename Model::State *state0 = &ret->state, *state1 = &aux_state;

  float score = m_ngram->Score(in_state, TranslateID(hypo.GetWord(position)), *state0);
  ++position;
  for (; position < adjust_end; ++position) {
    score += m_ngram->Score(*state0, TranslateID(hypo.GetWord(position)), *state1);
    std::swap(state0, state1);
  }

  if (hypo.IsSourceCompleted()) {
    // Score end of sentence.
    std::vector<lm::WordIndex> indices(m_ngram->Order() - 1);
    const lm::WordIndex *last = LastIDs(hypo, &indices.front());
    score += m_ngram->FullScoreForgotState(&indices.front(), last, m_ngram->GetVocabulary().EndSentence(), ret->state).prob;
  } else if (adjust_end < end) {
    // Get state after adding a long phrase.
    std::vector<lm::WordIndex> indices(m_ngram->Order() - 1);
    const lm::WordIndex *last = LastIDs(hypo, &indices.front());
    m_ngram->GetState(&indices.front(), last, ret->state);
  } else if (state0 != &ret->state) {
    // Short enough phrase that we can just reuse the state.
    ret->state = *state0;
  }

  score = TransformLMScore(score);

  if (OOVFeatureEnabled()) {
    std::vector<float> scores(2);
    scores[0] = score;
    scores[1] = 0.0;
    out->PlusEquals(this, scores);
  } else {
    out->PlusEquals(this, score);
  }

  return ret.release();
}

class LanguageModelChartStateKenLM : public FFState {
  public:
    LanguageModelChartStateKenLM() {}

    const lm::ngram::ChartState &GetChartState() const { return m_state; }
    lm::ngram::ChartState &GetChartState() { return m_state; }

    int Compare(const FFState& o) const
    {
      const LanguageModelChartStateKenLM &other = static_cast<const LanguageModelChartStateKenLM&>(o);
      int ret = m_state.Compare(other.m_state);
      return ret;
    }

  private:
    lm::ngram::ChartState m_state;
};

template <class Model> FFState *LanguageModelKen<Model>::EvaluateChart(const ChartHypothesis& hypo, int featureID, ScoreComponentCollection *accumulator) const {
  LanguageModelChartStateKenLM *newState = new LanguageModelChartStateKenLM();
  lm::ngram::RuleScore<Model> ruleScore(*m_ngram, newState->GetChartState());
  const AlignmentInfo::NonTermIndexMap &nonTermIndexMap = hypo.GetCurrTargetPhrase().GetAlignmentInfo().GetNonTermIndexMap();

  const size_t size = hypo.GetCurrTargetPhrase().GetSize();
  size_t phrasePos = 0;
  // Special cases for first word.
  if (size) {
    const Word &word = hypo.GetCurrTargetPhrase().GetWord(0);
    if (word.GetFactor(m_factorType) == m_beginSentenceFactor) {
      // Begin of sentence
      ruleScore.BeginSentence();
      phrasePos++;
    } else if (word.IsNonTerminal()) {
      // Non-terminal is first so we can copy instead of rescoring.
      const ChartHypothesis *prevHypo = hypo.GetPrevHypo(nonTermIndexMap[phrasePos]);
      const lm::ngram::ChartState &prevState = static_cast<const LanguageModelChartStateKenLM*>(prevHypo->GetFFState(featureID))->GetChartState();
      ruleScore.BeginNonTerminal(prevState, prevHypo->GetScoreBreakdown().GetScoresForProducer(this)[0]);
      phrasePos++;
    }
  }

  for (; phrasePos < size; phrasePos++) {
    const Word &word = hypo.GetCurrTargetPhrase().GetWord(phrasePos);
    if (word.IsNonTerminal()) {
      const ChartHypothesis *prevHypo = hypo.GetPrevHypo(nonTermIndexMap[phrasePos]);
      const lm::ngram::ChartState &prevState = static_cast<const LanguageModelChartStateKenLM*>(prevHypo->GetFFState(featureID))->GetChartState();
      ruleScore.NonTerminal(prevState, prevHypo->GetScoreBreakdown().GetScoresForProducer(this)[0]);
    } else {
      ruleScore.Terminal(TranslateID(word));
    }
  }

  accumulator->Assign(this, ruleScore.Finish());
  return newState;
}

} // namespace

LanguageModel *ConstructKenLM(const std::string &file, ScoreIndexManager &manager, FactorType factorType, bool lazy) {
  try {
    lm::ngram::ModelType model_type;
    if (lm::ngram::RecognizeBinary(file.c_str(), model_type)) {
      switch(model_type) {
        case lm::ngram::PROBING:
          return new LanguageModelKen<lm::ngram::ProbingModel>(file, manager, factorType, lazy);
        case lm::ngram::REST_PROBING:
          return new LanguageModelKen<lm::ngram::RestProbingModel>(file, manager, factorType, lazy);
        case lm::ngram::TRIE:
          return new LanguageModelKen<lm::ngram::TrieModel>(file, manager, factorType, lazy);
        case lm::ngram::QUANT_TRIE:
          return new LanguageModelKen<lm::ngram::QuantTrieModel>(file, manager, factorType, lazy);
        case lm::ngram::ARRAY_TRIE:
          return new LanguageModelKen<lm::ngram::ArrayTrieModel>(file, manager, factorType, lazy);
        case lm::ngram::QUANT_ARRAY_TRIE:
          return new LanguageModelKen<lm::ngram::QuantArrayTrieModel>(file, manager, factorType, lazy);
        default:
          std::cerr << "Unrecognized kenlm model type " << model_type << std::endl;
          abort();
      }
    } else {
      return new LanguageModelKen<lm::ngram::ProbingModel>(file, manager, factorType, lazy);
    }
  } catch (std::exception &e) {
    std::cerr << e.what() << std::endl;
    abort();
  }
}

}

<commit_msg>Rule score with left rest (default same)<commit_after>// $Id$

/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2006 University of Edinburgh

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/

#include <cstring>
#include <iostream>
#include <memory>
#include <stdlib.h>
#include "lm/binary_format.hh"
#include "lm/enumerate_vocab.hh"
#include "lm/left.hh"
#include "lm/model.hh"

#include "LM/Ken.h"
#include "LM/Base.h"
#include "FFState.h"
#include "TypeDef.h"
#include "Util.h"
#include "FactorCollection.h"
#include "Phrase.h"
#include "InputFileStream.h"
#include "StaticData.h"
#include "ChartHypothesis.h"

#include <boost/shared_ptr.hpp>

using namespace std;

namespace Moses {
namespace {

struct KenLMState : public FFState {
  lm::ngram::State state;
  int Compare(const FFState &o) const {
    const KenLMState &other = static_cast<const KenLMState &>(o);
    if (state.length < other.state.length) return -1;
    if (state.length > other.state.length) return 1;
    return std::memcmp(state.words, other.state.words, sizeof(lm::WordIndex) * state.length);
  }
};

/*
 * An implementation of single factor LM using Ken's code.
 */
template <class Model> class LanguageModelKen : public LanguageModel {
  public:
    LanguageModelKen(const std::string &file, ScoreIndexManager &manager, FactorType factorType, bool lazy);

    LanguageModel *Duplicate(ScoreIndexManager &scoreIndexManager) const;

    bool Useable(const Phrase &phrase) const {
      return (phrase.GetSize()>0 && phrase.GetFactor(0, m_factorType) != NULL);
    }

    std::string GetScoreProducerDescription(unsigned) const {
      std::ostringstream oss;
      oss << "LM_" << (unsigned)m_ngram->Order() << "gram";
      return oss.str();
    }

    const FFState *EmptyHypothesisState(const InputType &/*input*/) const {
      KenLMState *ret = new KenLMState();
      ret->state = m_ngram->BeginSentenceState();
      return ret;
    }

    void CalcScore(const Phrase &phrase, float &fullScore, float &ngramScore, size_t &oovCount) const;

    FFState *Evaluate(const Hypothesis &hypo, const FFState *ps, ScoreComponentCollection *out) const;

    FFState *EvaluateChart(const ChartHypothesis& cur_hypo, int featureID, ScoreComponentCollection *accumulator) const;

  private:
    LanguageModelKen(ScoreIndexManager &manager, const LanguageModelKen<Model> &copy_from);

    lm::WordIndex TranslateID(const Word &word) const {
      std::size_t factor = word.GetFactor(m_factorType)->GetId();
      return (factor >= m_lmIdLookup.size() ? 0 : m_lmIdLookup[factor]);
    }

    // Convert last words of hypothesis into vocab ids, returning an end pointer.
    lm::WordIndex *LastIDs(const Hypothesis &hypo, lm::WordIndex *indices) const {
      lm::WordIndex *index = indices;
      lm::WordIndex *end = indices + m_ngram->Order() - 1;
      int position = hypo.GetCurrTargetWordsRange().GetEndPos();
      for (; ; ++index, --position) {
        if (index == end) return index;
        if (position == -1) {
          *index = m_ngram->GetVocabulary().BeginSentence();
          return index + 1;
        }
        *index = TranslateID(hypo.GetWord(position));
      }
    }

    boost::shared_ptr<Model> m_ngram;

    std::vector<lm::WordIndex> m_lmIdLookup;

    FactorType m_factorType;

    const Factor *m_beginSentenceFactor;
};

class MappingBuilder : public lm::EnumerateVocab {
public:
  MappingBuilder(FactorCollection &factorCollection, std::vector<lm::WordIndex> &mapping)
    : m_factorCollection(factorCollection), m_mapping(mapping) {}

  void Add(lm::WordIndex index, const StringPiece &str) {
    std::size_t factorId = m_factorCollection.AddFactor(str)->GetId();
    if (m_mapping.size() <= factorId) {
      // 0 is <unk> :-)
      m_mapping.resize(factorId + 1);
    }
    m_mapping[factorId] = index;
  }

private:
  FactorCollection &m_factorCollection;
  std::vector<lm::WordIndex> &m_mapping;
};

template <class Model> LanguageModelKen<Model>::LanguageModelKen(const std::string &file, ScoreIndexManager &manager, FactorType factorType, bool lazy) : m_factorType(factorType) {
  lm::ngram::Config config;
  IFVERBOSE(1) {
    config.messages = &std::cerr;
  } else {
    config.messages = NULL;
  }
  FactorCollection &collection = FactorCollection::Instance();
  MappingBuilder builder(collection, m_lmIdLookup);
  config.enumerate_vocab = &builder;
  config.load_method = lazy ? util::LAZY : util::POPULATE_OR_READ;

  m_ngram.reset(new Model(file.c_str(), config));

  m_beginSentenceFactor = collection.AddFactor(BOS_);
  Init(manager);
}

template <class Model> LanguageModel *LanguageModelKen<Model>::Duplicate(ScoreIndexManager &manager) const {
  return new LanguageModelKen<Model>(manager, *this);
}

template <class Model> LanguageModelKen<Model>::LanguageModelKen(ScoreIndexManager &manager, const LanguageModelKen<Model> &copy_from) :
    m_ngram(copy_from.m_ngram),
    // TODO: don't copy this.
    m_lmIdLookup(copy_from.m_lmIdLookup),
    m_factorType(copy_from.m_factorType),
    m_beginSentenceFactor(copy_from.m_beginSentenceFactor) {
  Init(manager);
}

template <class Model> void LanguageModelKen<Model>::CalcScore(const Phrase &phrase, float &fullScore, float &ngramScore, size_t &oovCount) const {
  fullScore = 0;
  ngramScore = 0;
  oovCount = 0;

  if (!phrase.GetSize()) return;

  lm::ngram::ChartState discarded_sadly;
  lm::ngram::RuleScore<Model> scorer(*m_ngram, discarded_sadly);

  size_t position;
  if (m_beginSentenceFactor == phrase.GetWord(0).GetFactor(m_factorType)) {
    scorer.BeginSentence();
    position = 1;
  } else {
    position = 0;
  }

  size_t ngramBoundary = m_ngram->Order() - 1;

  size_t end_loop = std::min(ngramBoundary, phrase.GetSize());
  for (; position < end_loop; ++position) {
    const Word &word = phrase.GetWord(position);
    if (word.IsNonTerminal()) {
      fullScore += scorer.Finish();
      scorer.Reset();
    } else {
      lm::WordIndex index = TranslateID(word);
      scorer.Terminal(index);
      if (!index) ++oovCount;
    }
  }
  float before_boundary = fullScore + scorer.Finish();
  for (; position < phrase.GetSize(); ++position) {
     const Word &word = phrase.GetWord(position);
    if (word.IsNonTerminal()) {
      fullScore += scorer.Finish();
      scorer.Reset();
    } else {
      lm::WordIndex index = TranslateID(word);
      scorer.Terminal(index);
      if (!index) ++oovCount;
    }
  }
  fullScore += scorer.Finish();

  ngramScore = TransformLMScore(fullScore - before_boundary);
  fullScore = TransformLMScore(fullScore);
}

template <class Model> FFState *LanguageModelKen<Model>::Evaluate(const Hypothesis &hypo, const FFState *ps, ScoreComponentCollection *out) const {
  const lm::ngram::State &in_state = static_cast<const KenLMState&>(*ps).state;

  std::auto_ptr<KenLMState> ret(new KenLMState());

  if (!hypo.GetCurrTargetLength()) {
    ret->state = in_state;
    return ret.release();
  }

  const std::size_t begin = hypo.GetCurrTargetWordsRange().GetStartPos();
  //[begin, end) in STL-like fashion.
  const std::size_t end = hypo.GetCurrTargetWordsRange().GetEndPos() + 1;
  const std::size_t adjust_end = std::min(end, begin + m_ngram->Order() - 1);

  std::size_t position = begin;
  typename Model::State aux_state;
  typename Model::State *state0 = &ret->state, *state1 = &aux_state;

  float score = m_ngram->Score(in_state, TranslateID(hypo.GetWord(position)), *state0);
  ++position;
  for (; position < adjust_end; ++position) {
    score += m_ngram->Score(*state0, TranslateID(hypo.GetWord(position)), *state1);
    std::swap(state0, state1);
  }

  if (hypo.IsSourceCompleted()) {
    // Score end of sentence.
    std::vector<lm::WordIndex> indices(m_ngram->Order() - 1);
    const lm::WordIndex *last = LastIDs(hypo, &indices.front());
    score += m_ngram->FullScoreForgotState(&indices.front(), last, m_ngram->GetVocabulary().EndSentence(), ret->state).prob;
  } else if (adjust_end < end) {
    // Get state after adding a long phrase.
    std::vector<lm::WordIndex> indices(m_ngram->Order() - 1);
    const lm::WordIndex *last = LastIDs(hypo, &indices.front());
    m_ngram->GetState(&indices.front(), last, ret->state);
  } else if (state0 != &ret->state) {
    // Short enough phrase that we can just reuse the state.
    ret->state = *state0;
  }

  score = TransformLMScore(score);

  if (OOVFeatureEnabled()) {
    std::vector<float> scores(2);
    scores[0] = score;
    scores[1] = 0.0;
    out->PlusEquals(this, scores);
  } else {
    out->PlusEquals(this, score);
  }

  return ret.release();
}

class LanguageModelChartStateKenLM : public FFState {
  public:
    LanguageModelChartStateKenLM() {}

    const lm::ngram::ChartState &GetChartState() const { return m_state; }
    lm::ngram::ChartState &GetChartState() { return m_state; }

    int Compare(const FFState& o) const
    {
      const LanguageModelChartStateKenLM &other = static_cast<const LanguageModelChartStateKenLM&>(o);
      int ret = m_state.Compare(other.m_state);
      return ret;
    }

  private:
    lm::ngram::ChartState m_state;
};

template <class Model> FFState *LanguageModelKen<Model>::EvaluateChart(const ChartHypothesis& hypo, int featureID, ScoreComponentCollection *accumulator) const {
  LanguageModelChartStateKenLM *newState = new LanguageModelChartStateKenLM();
  lm::ngram::RuleScore<Model> ruleScore(*m_ngram, newState->GetChartState());
  const AlignmentInfo::NonTermIndexMap &nonTermIndexMap = hypo.GetCurrTargetPhrase().GetAlignmentInfo().GetNonTermIndexMap();

  const size_t size = hypo.GetCurrTargetPhrase().GetSize();
  size_t phrasePos = 0;
  // Special cases for first word.
  if (size) {
    const Word &word = hypo.GetCurrTargetPhrase().GetWord(0);
    if (word.GetFactor(m_factorType) == m_beginSentenceFactor) {
      // Begin of sentence
      ruleScore.BeginSentence();
      phrasePos++;
    } else if (word.IsNonTerminal()) {
      // Non-terminal is first so we can copy instead of rescoring.
      const ChartHypothesis *prevHypo = hypo.GetPrevHypo(nonTermIndexMap[phrasePos]);
      const lm::ngram::ChartState &prevState = static_cast<const LanguageModelChartStateKenLM*>(prevHypo->GetFFState(featureID))->GetChartState();
      ruleScore.BeginNonTerminal(prevState, prevHypo->GetScoreBreakdown().GetScoresForProducer(this)[0]);
      phrasePos++;
    }
  }

  for (; phrasePos < size; phrasePos++) {
    const Word &word = hypo.GetCurrTargetPhrase().GetWord(phrasePos);
    if (word.IsNonTerminal()) {
      const ChartHypothesis *prevHypo = hypo.GetPrevHypo(nonTermIndexMap[phrasePos]);
      const lm::ngram::ChartState &prevState = static_cast<const LanguageModelChartStateKenLM*>(prevHypo->GetFFState(featureID))->GetChartState();
      ruleScore.NonTerminal(prevState, prevHypo->GetScoreBreakdown().GetScoresForProducer(this)[0]);
    } else {
      ruleScore.Terminal(TranslateID(word));
    }
  }

  accumulator->Assign(this, ruleScore.Finish());
  return newState;
}

} // namespace

LanguageModel *ConstructKenLM(const std::string &file, ScoreIndexManager &manager, FactorType factorType, bool lazy) {
  try {
    lm::ngram::ModelType model_type;
    if (lm::ngram::RecognizeBinary(file.c_str(), model_type)) {
      switch(model_type) {
        case lm::ngram::PROBING:
          return new LanguageModelKen<lm::ngram::ProbingModel>(file, manager, factorType, lazy);
        case lm::ngram::REST_PROBING:
          return new LanguageModelKen<lm::ngram::RestProbingModel>(file, manager, factorType, lazy);
        case lm::ngram::TRIE:
          return new LanguageModelKen<lm::ngram::TrieModel>(file, manager, factorType, lazy);
        case lm::ngram::QUANT_TRIE:
          return new LanguageModelKen<lm::ngram::QuantTrieModel>(file, manager, factorType, lazy);
        case lm::ngram::ARRAY_TRIE:
          return new LanguageModelKen<lm::ngram::ArrayTrieModel>(file, manager, factorType, lazy);
        case lm::ngram::QUANT_ARRAY_TRIE:
          return new LanguageModelKen<lm::ngram::QuantArrayTrieModel>(file, manager, factorType, lazy);
        default:
          std::cerr << "Unrecognized kenlm model type " << model_type << std::endl;
          abort();
      }
    } else {
      return new LanguageModelKen<lm::ngram::ProbingModel>(file, manager, factorType, lazy);
    }
  } catch (std::exception &e) {
    std::cerr << e.what() << std::endl;
    abort();
  }
}

}

<|endoftext|>


<commit_before>// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wnon-pod-varargs

extern char version[];

class C {
public:
  C(int);
  void g(int a, ...);
  static void h(int a, ...);
};

void g(int a, ...);

void t1()
{
  C c(10);

  g(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
  g(10, version);
}

void t2()
{
  C c(10);

  c.g(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
  c.g(10, version);

  C::h(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
  C::h(10, version);
}

int (^block)(int, ...);

void t3()
{
  C c(10);

  block(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic block; call will abort at runtime}}
  block(10, version);
}

class D {
public:
  void operator() (int a, ...);
};

void t4()
{
  C c(10);

  D d;

  d(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
  d(10, version);
}

class E {
  E(int, ...);
};

void t5()
{
  C c(10);

  E e(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
  (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
}

// PR5761: unevaluated operands and the non-POD warning
class Foo {
 public:
  Foo() {}
};

int Helper(...);
const int size = sizeof(Helper(Foo()));

namespace std {
  class type_info { };
}

struct Base { virtual ~Base(); };
Base &get_base(...);
int eat_base(...);

void test_typeid(Base &base) {
  (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}}
  (void)typeid(eat_base(base)); // okay
}

// rdar://7985267 - Shouldn't warn, doesn't actually use __builtin_va_start is
// magic.

void t6(Foo somearg, ... ) {
  __builtin_va_start(0/*valist*/, somearg);
}

<commit_msg>really use valist.<commit_after>// RUN: %clang_cc1 -fsyntax-only -verify -fblocks %s -Wnon-pod-varargs

extern char version[];

class C {
public:
  C(int);
  void g(int a, ...);
  static void h(int a, ...);
};

void g(int a, ...);

void t1()
{
  C c(10);

  g(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
  g(10, version);
}

void t2()
{
  C c(10);

  c.g(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
  c.g(10, version);

  C::h(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic function; call will abort at runtime}}
  C::h(10, version);
}

int (^block)(int, ...);

void t3()
{
  C c(10);

  block(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic block; call will abort at runtime}}
  block(10, version);
}

class D {
public:
  void operator() (int a, ...);
};

void t4()
{
  C c(10);

  D d;

  d(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic method; call will abort at runtime}}
  d(10, version);
}

class E {
  E(int, ...);
};

void t5()
{
  C c(10);

  E e(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
  (void)E(10, c); // expected-warning{{cannot pass object of non-POD type 'C' through variadic constructor; call will abort at runtime}}
}

// PR5761: unevaluated operands and the non-POD warning
class Foo {
 public:
  Foo() {}
};

int Helper(...);
const int size = sizeof(Helper(Foo()));

namespace std {
  class type_info { };
}

struct Base { virtual ~Base(); };
Base &get_base(...);
int eat_base(...);

void test_typeid(Base &base) {
  (void)typeid(get_base(base)); // expected-warning{{cannot pass object of non-POD type 'Base' through variadic function; call will abort at runtime}}
  (void)typeid(eat_base(base)); // okay
}

// rdar://7985267 - Shouldn't warn, doesn't actually use __builtin_va_start is
// magic.

void t6(Foo somearg, ... ) {
  __builtin_va_list list;
  __builtin_va_start(list, somearg);
}

<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// insert_plan.cpp
//
// Identification: src/planner/insert_plan.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "planner/insert_plan.h"

#include "catalog/catalog.h"
#include "expression/constant_value_expression.h"
#include "storage/data_table.h"
#include "type/ephemeral_pool.h"
#include "type/value_factory.h"

namespace peloton {
namespace planner {

/**
 * @brief Create an insert plan
 *
 * @param[in] table          Table to insert into
 * @param[in] columns        Columns to insert into
 * @param[in] insert_values  Values
 */
InsertPlan::InsertPlan(storage::DataTable *table,
    const std::vector<std::string> *columns,
    const std::vector<std::vector<
        std::unique_ptr<expression::AbstractExpression>>> *insert_values)
    : target_table_(table), bulk_insert_count_(insert_values->size()) {
  LOG_TRACE("Creating an Insert Plan with multiple expressions");
  PL_ASSERT(target_table_);

  // We assume we are not processing a prepared statement insert.
  // Only after we have finished processing, do we know if it is a
  // PS or not a PS.
  bool is_prepared_stmt = false;
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();
  vtos_.resize(insert_values->size());
  // initialize mapping from schema cols to insert values vector.
  // will be updated later based on insert columns and values
  stov_.resize(schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    stov_[idx].in_insert_cols = false;
    stov_[idx].set_value = false;
    stov_[idx].val_idx = 0;
    // remember the column types
    stov_[idx].type = schema->GetType(idx);
  }

  if (columns->empty()) {
    // INSERT INTO table_name VALUES (val1, val2, ...), (val1, val2, ...)
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);
      // uint32_t param_idx = 0;
      for (uint32_t column_id = 0; column_id < values.size(); column_id++) {

        auto &exp = values[column_id];
	auto exp_ptr = exp.get();
	auto ret_bool = ProcessValueExpr(exp_ptr, column_id);
	// there is no column specification, so we have a
	// direct mapping between schema cols and the value vector
	stov_[column_id].in_insert_cols = true;
	stov_[column_id].val_idx = column_id;
	if (ret_bool == true) {
	  is_prepared_stmt = true;
	}
      }
    }
  } else {
    // INSERT INTO table_name (col1, col2, ...) VALUES (val1, val2, ...);
    // Columns may be in any order. Values may include constants.
    PL_ASSERT(columns->size() <= schema_col_count);
    // construct the mapping between schema cols and insert cols
    ProcessColumnSpec(columns);
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);

      for (uint32_t idx = 0; idx < schema_col_count; idx++) {
	if (stov_[idx].in_insert_cols) {
	  // this schema column is present in the insert columns spec.
	  // get index into values
	  auto val_idx = stov_[idx].val_idx;
	  auto &exp = values[val_idx];
	  auto exp_ptr = exp.get();
	  bool ret_bool = ProcessValueExpr(exp_ptr, idx);
	  if (ret_bool) {
	    is_prepared_stmt = true;
	  }
	}
	else {
	  // schema column not present in insert columns spec. Set
	  // column to its default value
	  SetDefaultValue(idx);
	}
      }

      if (is_prepared_stmt) {
	// Adjust indexes into values. When constants are present in the
	// value tuple spec., the value vector supplied by the prepared
	// statement when SetParameterValues is called, will be smaller.
	// It will not include any of the constants.
	// Adjust the mapping from schema cols -> values vector to exclude
	// the constant columns. If there are no constants, this is a no-op.
	uint32_t adjust = 0;
	for (uint32_t idx=0; idx < columns->size(); idx++) {
	  uint32_t stov_idx = vtos_[idx];
	  if (stov_[stov_idx].set_value) {
	    // constant, not present in PS values
	    adjust++;
	  } else {
	    // adjust the index
	    stov_[stov_idx].val_idx -= adjust;
	  }
	}
      }
    }
  }
  if (is_prepared_stmt) {
    // We've been assuming it is not a PS and saving into the values_
    // vector. Now that we know it is a PS, we must clear those values
    // so SetParameterValues will operate correctly.
    ClearParameterValues();
  }
}

/**
 * Process column specification supplied in the insert statement.
 * Construct a map from insert columns to schema columns. Once
 * we know which columns will receive constant inserts, further
 * adjustment of the map will be needed.
 *
 * @param[in] columns        Column specification
 */
void InsertPlan::ProcessColumnSpec(const std::vector<std::string> *columns) {
  auto *schema = target_table_->GetSchema();
  auto &table_columns = schema->GetColumns();
  auto usr_col_count = columns->size();

  // iterate over supplied columns
  for (size_t usr_col_id = 0; usr_col_id < usr_col_count; usr_col_id++) {
    uint32_t idx;
    auto col_name = columns->at(usr_col_id);

    // determine index of column in schema
    bool found_col = FindSchemaColIndex(col_name, table_columns, idx);
    // PL_ASSERT(found_col == true);
    if (not found_col) {
      throw Exception{
	StringUtil::Format("column %s not in table %s columns",
			   col_name,
			   target_table_->GetName())};
    }
    // we have values for this column
    stov_[idx].in_insert_cols = true;
    // remember how to map schema col -> value for col in tuple
    stov_[idx].val_idx = usr_col_id;
    // and the reverse
    vtos_[usr_col_id] = idx;
  }
}

/**
 * Process a single expression to be inserted.
 *
 * @param[in] expr       insert expression
 * @param[in] schema_idx index into schema columns, where the expr
 *                       will be inserted.
 * @return  true if values imply a prepared statement
 *          false if all values are constants. This does not rule
 *             out the insert being a prepared statement.
 */
bool InsertPlan::ProcessValueExpr(expression::AbstractExpression *expr,
				  uint32_t schema_idx) {
  auto type = stov_[schema_idx].type;

  if (expr == nullptr) {
    SetDefaultValue(schema_idx);
  } else if (expr->GetExpressionType() == ExpressionType::VALUE_CONSTANT) {

    auto *const_expr =
      dynamic_cast<expression::ConstantValueExpression *>(expr);
    type::Value value = const_expr->GetValue().CastAs(type);

    stov_[schema_idx].set_value = true;
    stov_[schema_idx].value = value;
    // save it, in case this is not a PS
    values_.push_back(value);

    return false;
  } else {
    PL_ASSERT(expr->GetExpressionType() == ExpressionType::VALUE_PARAMETER);
    return true;
  }
  return false;
}

/**
 * Set default value into a schema column
 *
 * @param[in] idx  schema column index
 */
void InsertPlan::SetDefaultValue(uint32_t idx) {
  auto *schema = target_table_->GetSchema();
  type::Value *v = schema->GetDefaultValue(idx);
  type::TypeId type = stov_[idx].type;

  if (v == nullptr)
    // null default value
    values_.push_back(type::ValueFactory::GetNullValueByType(type));
  else
    // non-null default value
    values_.push_back(*v);
}

/**
 * Lookup a column name in the schema columns
 *
 * @param[in]  col_name    column name, from insert statement
 * @param[in]  tbl_columns table columns from the schema
 * @param[out] index       index into schema columns, only if found
 *
 * @return      true if column was found, false otherwise
 */
bool InsertPlan::FindSchemaColIndex(std::string col_name,
				    const std::vector<catalog::Column> &tbl_columns,
				    uint32_t &index) {
  for (auto tcol = tbl_columns.begin(); tcol != tbl_columns.end(); tcol++) {
    if (tcol->GetName() == col_name) {
      index = std::distance(tbl_columns.begin(), tcol);
      return true;
    }
  }
  return false;
}

type::AbstractPool *InsertPlan::GetPlanPool() {
  if (pool_.get() == nullptr)
    pool_.reset(new type::EphemeralPool());
  return pool_.get();
}

/**
 * @brief Save values for jdbc prepared statement insert.
 *    Only a single tuple is presented to this function.
 *
 * @param[in] values  Values for insertion
 */
void InsertPlan::SetParameterValues(std::vector<type::Value> *values) {
  LOG_TRACE("Set Parameter Values in Insert");
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();

  PL_ASSERT(values->size() <= schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    if (stov_[idx].set_value) {
      values_.push_back(stov_[idx].value);
    } else if (stov_[idx].in_insert_cols) {
      // get index into values
      auto val_idx = stov_[idx].val_idx;
      auto type = stov_[idx].type;
      type::Value value = values->at(val_idx).CastAs(type);
      values_.push_back(value);
    } else {
      // not in insert cols, set default value
      SetDefaultValue(idx);
    }
  }
}

void InsertPlan::PerformBinding(BindingContext &binding_context) {
  const auto &children = GetChildren();

  if (children.size() == 1) {
    children[0]->PerformBinding(binding_context);

    auto *scan = static_cast<planner::AbstractScan *>(children[0].get());
    auto &col_ids = scan->GetColumnIds();
    for (oid_t col_id = 0; col_id < col_ids.size(); col_id++) {
      ais_.push_back(binding_context.Find(col_id));
    }
  }
  // Binding is not required if there is no child
}

hash_t InsertPlan::Hash() const {
  auto type = GetPlanNodeType();
  hash_t hash = HashUtil::Hash(&type);

  hash = HashUtil::CombineHashes(hash, GetTable()->Hash());
  if (GetChildren().size() == 0) {
    auto bulk_insert_count = GetBulkInsertCount();
    hash = HashUtil::CombineHashes(hash, HashUtil::Hash(&bulk_insert_count));
  }

  return HashUtil::CombineHashes(hash, AbstractPlan::Hash());
}

bool InsertPlan::operator==(const AbstractPlan &rhs) const {
  if (GetPlanNodeType() != rhs.GetPlanNodeType())
    return false;

  auto &other = static_cast<const planner::InsertPlan &>(rhs);

  auto *table = GetTable();
  auto *other_table = other.GetTable();
  PL_ASSERT(table && other_table);
  if (*table != *other_table)
    return false;

  if (GetChildren().size() == 0) {
    if (other.GetChildren().size() != 0)
      return false;

    if (GetBulkInsertCount() != other.GetBulkInsertCount())
      return false;
  }

  return AbstractPlan::operator==(rhs);
}

void InsertPlan::VisitParameters(
    codegen::QueryParametersMap &map, std::vector<peloton::type::Value> &values,
    const std::vector<peloton::type::Value> &values_from_user) {
  if (GetChildren().size() == 0) {
    auto *schema = target_table_->GetSchema();
    auto columns_num = schema->GetColumnCount();

    for (uint32_t i = 0; i < values_.size(); i++) {
      auto value = values_[i];
      auto column_id = i % columns_num;
      map.Insert(expression::Parameter::CreateConstParameter(value.GetTypeId(),
          schema->AllowNull(column_id)), nullptr);
      values.push_back(value);
    }
  } else {
    PL_ASSERT(GetChildren().size() == 1);
    auto *plan = const_cast<planner::AbstractPlan *>(GetChild(0));
    plan->VisitParameters(map, values, values_from_user);
  }
}

}  // namespace planner
}  // namespace peloton
<commit_msg>Compile fix for Ubuntu Trusty, gcc 4.8<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// insert_plan.cpp
//
// Identification: src/planner/insert_plan.cpp
//
// Copyright (c) 2015-17, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include "planner/insert_plan.h"

#include "catalog/catalog.h"
#include "expression/constant_value_expression.h"
#include "storage/data_table.h"
#include "type/ephemeral_pool.h"
#include "type/value_factory.h"

namespace peloton {
namespace planner {

/**
 * @brief Create an insert plan
 *
 * @param[in] table          Table to insert into
 * @param[in] columns        Columns to insert into
 * @param[in] insert_values  Values
 */
InsertPlan::InsertPlan(storage::DataTable *table,
    const std::vector<std::string> *columns,
    const std::vector<std::vector<
        std::unique_ptr<expression::AbstractExpression>>> *insert_values)
    : target_table_(table), bulk_insert_count_(insert_values->size()) {
  LOG_TRACE("Creating an Insert Plan with multiple expressions");
  PL_ASSERT(target_table_);

  // We assume we are not processing a prepared statement insert.
  // Only after we have finished processing, do we know if it is a
  // PS or not a PS.
  bool is_prepared_stmt = false;
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();
  vtos_.resize(insert_values->size());
  // initialize mapping from schema cols to insert values vector.
  // will be updated later based on insert columns and values
  stov_.resize(schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    stov_[idx].in_insert_cols = false;
    stov_[idx].set_value = false;
    stov_[idx].val_idx = 0;
    // remember the column types
    stov_[idx].type = schema->GetType(idx);
  }

  if (columns->empty()) {
    // INSERT INTO table_name VALUES (val1, val2, ...), (val1, val2, ...)
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);
      // uint32_t param_idx = 0;
      for (uint32_t column_id = 0; column_id < values.size(); column_id++) {

        auto &exp = values[column_id];
	auto exp_ptr = exp.get();
	auto ret_bool = ProcessValueExpr(exp_ptr, column_id);
	// there is no column specification, so we have a
	// direct mapping between schema cols and the value vector
	stov_[column_id].in_insert_cols = true;
	stov_[column_id].val_idx = column_id;
	if (ret_bool == true) {
	  is_prepared_stmt = true;
	}
      }
    }
  } else {
    // INSERT INTO table_name (col1, col2, ...) VALUES (val1, val2, ...);
    // Columns may be in any order. Values may include constants.
    PL_ASSERT(columns->size() <= schema_col_count);
    // construct the mapping between schema cols and insert cols
    ProcessColumnSpec(columns);
    for (uint32_t tuple_idx = 0; tuple_idx < insert_values->size();
         tuple_idx++) {
      auto &values = (*insert_values)[tuple_idx];
      PL_ASSERT(values.size() <= schema_col_count);

      for (uint32_t idx = 0; idx < schema_col_count; idx++) {
	if (stov_[idx].in_insert_cols) {
	  // this schema column is present in the insert columns spec.
	  // get index into values
	  auto val_idx = stov_[idx].val_idx;
	  auto &exp = values[val_idx];
	  auto exp_ptr = exp.get();
	  bool ret_bool = ProcessValueExpr(exp_ptr, idx);
	  if (ret_bool) {
	    is_prepared_stmt = true;
	  }
	}
	else {
	  // schema column not present in insert columns spec. Set
	  // column to its default value
	  SetDefaultValue(idx);
	}
      }

      if (is_prepared_stmt) {
	// Adjust indexes into values. When constants are present in the
	// value tuple spec., the value vector supplied by the prepared
	// statement when SetParameterValues is called, will be smaller.
	// It will not include any of the constants.
	// Adjust the mapping from schema cols -> values vector to exclude
	// the constant columns. If there are no constants, this is a no-op.
	uint32_t adjust = 0;
	for (uint32_t idx=0; idx < columns->size(); idx++) {
	  uint32_t stov_idx = vtos_[idx];
	  if (stov_[stov_idx].set_value) {
	    // constant, not present in PS values
	    adjust++;
	  } else {
	    // adjust the index
	    stov_[stov_idx].val_idx -= adjust;
	  }
	}
      }
    }
  }
  if (is_prepared_stmt) {
    // We've been assuming it is not a PS and saving into the values_
    // vector. Now that we know it is a PS, we must clear those values
    // so SetParameterValues will operate correctly.
    ClearParameterValues();
  }
}

/**
 * Process column specification supplied in the insert statement.
 * Construct a map from insert columns to schema columns. Once
 * we know which columns will receive constant inserts, further
 * adjustment of the map will be needed.
 *
 * @param[in] columns        Column specification
 */
void InsertPlan::ProcessColumnSpec(const std::vector<std::string> *columns) {
  auto *schema = target_table_->GetSchema();
  auto &table_columns = schema->GetColumns();
  auto usr_col_count = columns->size();

  // iterate over supplied columns
  for (size_t usr_col_id = 0; usr_col_id < usr_col_count; usr_col_id++) {
    uint32_t idx;
    auto col_name = columns->at(usr_col_id);

    // determine index of column in schema
    bool found_col = FindSchemaColIndex(col_name, table_columns, idx);
    // PL_ASSERT(found_col == true);
    if (not found_col) {
      throw Exception{
	StringUtil::Format("column %s not in table %s columns",
			   col_name,
			   target_table_->GetName().c_str())};
    }
    // we have values for this column
    stov_[idx].in_insert_cols = true;
    // remember how to map schema col -> value for col in tuple
    stov_[idx].val_idx = usr_col_id;
    // and the reverse
    vtos_[usr_col_id] = idx;
  }
}

/**
 * Process a single expression to be inserted.
 *
 * @param[in] expr       insert expression
 * @param[in] schema_idx index into schema columns, where the expr
 *                       will be inserted.
 * @return  true if values imply a prepared statement
 *          false if all values are constants. This does not rule
 *             out the insert being a prepared statement.
 */
bool InsertPlan::ProcessValueExpr(expression::AbstractExpression *expr,
				  uint32_t schema_idx) {
  auto type = stov_[schema_idx].type;

  if (expr == nullptr) {
    SetDefaultValue(schema_idx);
  } else if (expr->GetExpressionType() == ExpressionType::VALUE_CONSTANT) {

    auto *const_expr =
      dynamic_cast<expression::ConstantValueExpression *>(expr);
    type::Value value = const_expr->GetValue().CastAs(type);

    stov_[schema_idx].set_value = true;
    stov_[schema_idx].value = value;
    // save it, in case this is not a PS
    values_.push_back(value);

    return false;
  } else {
    PL_ASSERT(expr->GetExpressionType() == ExpressionType::VALUE_PARAMETER);
    return true;
  }
  return false;
}

/**
 * Set default value into a schema column
 *
 * @param[in] idx  schema column index
 */
void InsertPlan::SetDefaultValue(uint32_t idx) {
  auto *schema = target_table_->GetSchema();
  type::Value *v = schema->GetDefaultValue(idx);
  type::TypeId type = stov_[idx].type;

  if (v == nullptr)
    // null default value
    values_.push_back(type::ValueFactory::GetNullValueByType(type));
  else
    // non-null default value
    values_.push_back(*v);
}

/**
 * Lookup a column name in the schema columns
 *
 * @param[in]  col_name    column name, from insert statement
 * @param[in]  tbl_columns table columns from the schema
 * @param[out] index       index into schema columns, only if found
 *
 * @return      true if column was found, false otherwise
 */
bool InsertPlan::FindSchemaColIndex(std::string col_name,
				    const std::vector<catalog::Column> &tbl_columns,
				    uint32_t &index) {
  for (auto tcol = tbl_columns.begin(); tcol != tbl_columns.end(); tcol++) {
    if (tcol->GetName() == col_name) {
      index = std::distance(tbl_columns.begin(), tcol);
      return true;
    }
  }
  return false;
}

type::AbstractPool *InsertPlan::GetPlanPool() {
  if (pool_.get() == nullptr)
    pool_.reset(new type::EphemeralPool());
  return pool_.get();
}

/**
 * @brief Save values for jdbc prepared statement insert.
 *    Only a single tuple is presented to this function.
 *
 * @param[in] values  Values for insertion
 */
void InsertPlan::SetParameterValues(std::vector<type::Value> *values) {
  LOG_TRACE("Set Parameter Values in Insert");
  auto *schema = target_table_->GetSchema();
  auto schema_col_count = schema->GetColumnCount();

  PL_ASSERT(values->size() <= schema_col_count);
  for (uint32_t idx = 0; idx < schema_col_count; idx++) {
    if (stov_[idx].set_value) {
      values_.push_back(stov_[idx].value);
    } else if (stov_[idx].in_insert_cols) {
      // get index into values
      auto val_idx = stov_[idx].val_idx;
      auto type = stov_[idx].type;
      type::Value value = values->at(val_idx).CastAs(type);
      values_.push_back(value);
    } else {
      // not in insert cols, set default value
      SetDefaultValue(idx);
    }
  }
}

void InsertPlan::PerformBinding(BindingContext &binding_context) {
  const auto &children = GetChildren();

  if (children.size() == 1) {
    children[0]->PerformBinding(binding_context);

    auto *scan = static_cast<planner::AbstractScan *>(children[0].get());
    auto &col_ids = scan->GetColumnIds();
    for (oid_t col_id = 0; col_id < col_ids.size(); col_id++) {
      ais_.push_back(binding_context.Find(col_id));
    }
  }
  // Binding is not required if there is no child
}

hash_t InsertPlan::Hash() const {
  auto type = GetPlanNodeType();
  hash_t hash = HashUtil::Hash(&type);

  hash = HashUtil::CombineHashes(hash, GetTable()->Hash());
  if (GetChildren().size() == 0) {
    auto bulk_insert_count = GetBulkInsertCount();
    hash = HashUtil::CombineHashes(hash, HashUtil::Hash(&bulk_insert_count));
  }

  return HashUtil::CombineHashes(hash, AbstractPlan::Hash());
}

bool InsertPlan::operator==(const AbstractPlan &rhs) const {
  if (GetPlanNodeType() != rhs.GetPlanNodeType())
    return false;

  auto &other = static_cast<const planner::InsertPlan &>(rhs);

  auto *table = GetTable();
  auto *other_table = other.GetTable();
  PL_ASSERT(table && other_table);
  if (*table != *other_table)
    return false;

  if (GetChildren().size() == 0) {
    if (other.GetChildren().size() != 0)
      return false;

    if (GetBulkInsertCount() != other.GetBulkInsertCount())
      return false;
  }

  return AbstractPlan::operator==(rhs);
}

void InsertPlan::VisitParameters(
    codegen::QueryParametersMap &map, std::vector<peloton::type::Value> &values,
    const std::vector<peloton::type::Value> &values_from_user) {
  if (GetChildren().size() == 0) {
    auto *schema = target_table_->GetSchema();
    auto columns_num = schema->GetColumnCount();

    for (uint32_t i = 0; i < values_.size(); i++) {
      auto value = values_[i];
      auto column_id = i % columns_num;
      map.Insert(expression::Parameter::CreateConstParameter(value.GetTypeId(),
          schema->AllowNull(column_id)), nullptr);
      values.push_back(value);
    }
  } else {
    PL_ASSERT(GetChildren().size() == 1);
    auto *plan = const_cast<planner::AbstractPlan *>(GetChild(0));
    plan->VisitParameters(map, values, values_from_user);
  }
}

}  // namespace planner
}  // namespace peloton
<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "PolyLineNode.h"

#include "NodeDefinition.h"

#include "../graphics/VertexArray.h"
#include "../base/Exception.h"
#include "../base/GeomHelper.h"
#include "../base/Triangle.h"

#include <iostream>
#include <sstream>

using namespace std;

namespace avg {

NodeDefinition PolyLineNode::createDefinition()
{
    return NodeDefinition("polyline", Node::buildNode<PolyLineNode>)
        .extendDefinition(VectorNode::createDefinition())
        .addArg(Arg<string>("linejoin", "bevel"))
        ;
}

PolyLineNode::PolyLineNode(const ArgList& Args, bool bFromXML)
{
    Args.setMembers(this);
    setLineJoin(Args.getArgVal<string>("linejoin"));
}

PolyLineNode::PolyLineNode()
{
}

PolyLineNode::~PolyLineNode()
{
}

const vector<DPoint>& PolyLineNode::getPos() const
{
    return m_Pts;
}

void PolyLineNode::setPos(const vector<DPoint>& pts)
{
    m_Pts.clear();
    m_Pts.reserve(pts.size());
    if (!pts.empty()) {
        m_Pts.push_back(pts[0]);
        // Remove possible duplicated points.
        for (unsigned int i=1; i<pts.size(); ++i) {
            if (pts[i] != pts[i-1]) {
                m_Pts.push_back(pts[i]);
            }
        }
    }
    setDrawNeeded(true);
}

string PolyLineNode::getLineJoin() const
{
    switch(m_LineJoin) {
        case LJ_MITER:
            return "miter";
        case LJ_BEVEL:
            return "bevel";
        default:
            assert(false);
    }
}

void PolyLineNode::setLineJoin(const string& sAlign)
{
    if (sAlign == "miter") {
        m_LineJoin = LJ_MITER;
    } else if (sAlign == "bevel") {
        m_LineJoin = LJ_BEVEL;
    } else {
        throw(Exception(AVG_ERR_UNSUPPORTED,
                "Vector linejoin "+sAlign+" not supported."));
    }
    setDrawNeeded(true);
}

int PolyLineNode::getNumVertexes()
{
    if (m_Pts.size() < 2) {
        return 0;
    }
    switch (m_LineJoin) {
        case LJ_MITER:
            return 2*m_Pts.size();
        case LJ_BEVEL:
            return 3*m_Pts.size()-2;
        default:
            assert(false);
    }

}

int PolyLineNode::getNumIndexes()
{
    if (m_Pts.size() < 2) {
        return 0;
    }
    switch (m_LineJoin) {
        case LJ_MITER:
            return 6*(m_Pts.size()-1);
        case LJ_BEVEL:
            return 3*(3*m_Pts.size()-4);
        default:
            assert(false);
    }
}

void PolyLineNode::calcVertexes(VertexDataPtr& pVertexData, double opacity)
{
    if (m_Pts.size() < 2) {
        return;
    }
    double curOpacity = opacity*getOpacity();
    Pixel32 color = getColorVal();
    color.setA((unsigned char)(curOpacity*255));

    int numPts = m_Pts.size();

    vector<WideLine> lines;
    lines.reserve(numPts-1);
    for (int i=0; i<numPts-1; ++i) {
        lines.push_back(WideLine(m_Pts[i], m_Pts[i+1], getStrokeWidth()));
    }

    pVertexData->appendPos(lines[0].pl0, DPoint(0,0), color);
    pVertexData->appendPos(lines[0].pr0, DPoint(0,0), color);
    for (int i=0; i<numPts-2; ++i) {
        const WideLine& line1 = lines[i];
        const WideLine& line2 = lines[i+1];
        DPoint pli = getLineLineIntersection(line1.pl0, line1.dir, line2.pl0, line2.dir);
        DPoint pri = getLineLineIntersection(line1.pr0, line1.dir, line2.pr0, line2.dir);

        int curVertex = pVertexData->getCurVert();
        switch (m_LineJoin) {
            case LJ_MITER:
                pVertexData->appendPos(pli, DPoint(0,0), color);
                pVertexData->appendPos(pri, DPoint(0,0), color);
                pVertexData->appendQuadIndexes(
                        curVertex-1, curVertex-2, curVertex+1, curVertex);
                break;
            case LJ_BEVEL:
                {
                    Triangle tri(line1.pl1, line2.pl0, pri);
                    if (tri.isClockwise()) {
                        pVertexData->appendPos(line1.pl1, DPoint(0,0), color);
                        pVertexData->appendPos(line2.pl0, DPoint(0,0), color);
                        pVertexData->appendPos(pri, DPoint(0,0), color);
                        pVertexData->appendQuadIndexes(
                                curVertex-1, curVertex-2, curVertex+2, curVertex);
                        pVertexData->appendTriIndexes(
                                curVertex, curVertex+1, curVertex+2);
                    } else {
                        pVertexData->appendPos(line1.pr1, DPoint(0,0), color);
                        pVertexData->appendPos(pli, DPoint(0,0), color);
                        pVertexData->appendPos(line2.pr0, DPoint(0,0), color);
                        pVertexData->appendQuadIndexes(
                                curVertex-2, curVertex-1, curVertex+1, curVertex);
                        pVertexData->appendTriIndexes(
                                curVertex, curVertex+1, curVertex+2);
                    }
                }
                break;
            default:
                assert(false);
        }
    }
    int curVertex = pVertexData->getCurVert();
    pVertexData->appendPos(lines[numPts-2].pl1, DPoint(0,0), color);
    pVertexData->appendPos(lines[numPts-2].pr1, DPoint(0,0), color);
    pVertexData->appendQuadIndexes(curVertex-1, curVertex-2, curVertex+1, curVertex);
}

PolyLineNode::LineJoin PolyLineNode::getLineJoinEnum() const
{
    return m_LineJoin;
}

}
<commit_msg>PolyLineNode.cpp: avoid msvc warnings.<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "PolyLineNode.h"

#include "NodeDefinition.h"

#include "../graphics/VertexArray.h"
#include "../base/Exception.h"
#include "../base/GeomHelper.h"
#include "../base/Triangle.h"

#include <iostream>
#include <sstream>

using namespace std;

namespace avg {

NodeDefinition PolyLineNode::createDefinition()
{
    return NodeDefinition("polyline", Node::buildNode<PolyLineNode>)
        .extendDefinition(VectorNode::createDefinition())
        .addArg(Arg<string>("linejoin", "bevel"))
        ;
}

PolyLineNode::PolyLineNode(const ArgList& Args, bool bFromXML)
{
    Args.setMembers(this);
    setLineJoin(Args.getArgVal<string>("linejoin"));
}

PolyLineNode::PolyLineNode()
{
}

PolyLineNode::~PolyLineNode()
{
}

const vector<DPoint>& PolyLineNode::getPos() const
{
    return m_Pts;
}

void PolyLineNode::setPos(const vector<DPoint>& pts)
{
    m_Pts.clear();
    m_Pts.reserve(pts.size());
    if (!pts.empty()) {
        m_Pts.push_back(pts[0]);
        // Remove possible duplicated points.
        for (unsigned int i=1; i<pts.size(); ++i) {
            if (pts[i] != pts[i-1]) {
                m_Pts.push_back(pts[i]);
            }
        }
    }
    setDrawNeeded(true);
}

string PolyLineNode::getLineJoin() const
{
    switch(m_LineJoin) {
        case LJ_MITER:
            return "miter";
        case LJ_BEVEL:
            return "bevel";
        default:
            assert(false);
            return 0;
    }
}

void PolyLineNode::setLineJoin(const string& sAlign)
{
    if (sAlign == "miter") {
        m_LineJoin = LJ_MITER;
    } else if (sAlign == "bevel") {
        m_LineJoin = LJ_BEVEL;
    } else {
        throw(Exception(AVG_ERR_UNSUPPORTED,
                "Vector linejoin "+sAlign+" not supported."));
    }
    setDrawNeeded(true);
}

int PolyLineNode::getNumVertexes()
{
    if (m_Pts.size() < 2) {
        return 0;
    }
    switch (m_LineJoin) {
        case LJ_MITER:
            return 2*m_Pts.size();
        case LJ_BEVEL:
            return 3*m_Pts.size()-2;
        default:
            assert(false);
            return 0;
    }

}

int PolyLineNode::getNumIndexes()
{
    if (m_Pts.size() < 2) {
        return 0;
    }
    switch (m_LineJoin) {
        case LJ_MITER:
            return 6*(m_Pts.size()-1);
        case LJ_BEVEL:
            return 3*(3*m_Pts.size()-4);
        default:
            assert(false);
            return 0;
    }
}

void PolyLineNode::calcVertexes(VertexDataPtr& pVertexData, double opacity)
{
    if (m_Pts.size() < 2) {
        return;
    }
    double curOpacity = opacity*getOpacity();
    Pixel32 color = getColorVal();
    color.setA((unsigned char)(curOpacity*255));

    int numPts = m_Pts.size();

    vector<WideLine> lines;
    lines.reserve(numPts-1);
    for (int i=0; i<numPts-1; ++i) {
        lines.push_back(WideLine(m_Pts[i], m_Pts[i+1], getStrokeWidth()));
    }

    pVertexData->appendPos(lines[0].pl0, DPoint(0,0), color);
    pVertexData->appendPos(lines[0].pr0, DPoint(0,0), color);
    for (int i=0; i<numPts-2; ++i) {
        const WideLine& line1 = lines[i];
        const WideLine& line2 = lines[i+1];
        DPoint pli = getLineLineIntersection(line1.pl0, line1.dir, line2.pl0, line2.dir);
        DPoint pri = getLineLineIntersection(line1.pr0, line1.dir, line2.pr0, line2.dir);

        int curVertex = pVertexData->getCurVert();
        switch (m_LineJoin) {
            case LJ_MITER:
                pVertexData->appendPos(pli, DPoint(0,0), color);
                pVertexData->appendPos(pri, DPoint(0,0), color);
                pVertexData->appendQuadIndexes(
                        curVertex-1, curVertex-2, curVertex+1, curVertex);
                break;
            case LJ_BEVEL:
                {
                    Triangle tri(line1.pl1, line2.pl0, pri);
                    if (tri.isClockwise()) {
                        pVertexData->appendPos(line1.pl1, DPoint(0,0), color);
                        pVertexData->appendPos(line2.pl0, DPoint(0,0), color);
                        pVertexData->appendPos(pri, DPoint(0,0), color);
                        pVertexData->appendQuadIndexes(
                                curVertex-1, curVertex-2, curVertex+2, curVertex);
                        pVertexData->appendTriIndexes(
                                curVertex, curVertex+1, curVertex+2);
                    } else {
                        pVertexData->appendPos(line1.pr1, DPoint(0,0), color);
                        pVertexData->appendPos(pli, DPoint(0,0), color);
                        pVertexData->appendPos(line2.pr0, DPoint(0,0), color);
                        pVertexData->appendQuadIndexes(
                                curVertex-2, curVertex-1, curVertex+1, curVertex);
                        pVertexData->appendTriIndexes(
                                curVertex, curVertex+1, curVertex+2);
                    }
                }
                break;
            default:
                assert(false);
        }
    }
    int curVertex = pVertexData->getCurVert();
    pVertexData->appendPos(lines[numPts-2].pl1, DPoint(0,0), color);
    pVertexData->appendPos(lines[numPts-2].pr1, DPoint(0,0), color);
    pVertexData->appendQuadIndexes(curVertex-1, curVertex-2, curVertex+1, curVertex);
}

PolyLineNode::LineJoin PolyLineNode::getLineJoinEnum() const
{
    return m_LineJoin;
}

}
<|endoftext|>


<commit_before>// This file is part of Playslave-C++.
// Playslave-C++ is licenced under the MIT license: see LICENSE.txt.

/**
* @file
* Declaration of the PlayerState class, and associated types.
* @see player/player_state.cpp
*/

#ifndef PS_PLAYER_STATE_HPP
#define PS_PLAYER_STATE_HPP

#include <cstdint>
#include <initializer_list>
#include <functional>
#include <boost/optional.hpp>

#include "../io/io_response.hpp"

/**
 * An object holding and representing the current state of a Player.
 * @see Player
 * @see PlayerPosition
 */
class PlayerState : public ResponseSource {
public:
	/**
	 * Enumeration of states that the player can be in.
	 * The player is effectively a finite-state machine whose behaviour
	 * at any given time is dictated by the current state, which is
	 * represented by an instance of State.
	 */
	enum class State : std::uint8_t {
		STARTING, ///< The player has just initialised.
		EJECTED,  ///< The player has no song loaded.
		STOPPED,  ///< The player has a song loaded and not playing.
		PLAYING,  ///< The player has a song loaded and playing.
		QUITTING  ///< The player is about to terminate.
	};

	/// A list of states, used for IfIn.
	using List = std::initializer_list<State>;

	/// List of states in which the player is playing something.
	const static List AUDIO_PLAYING_STATES;

	/// List of states in which some audio is loaded.
	const static List AUDIO_LOADED_STATES;

	/// Constructs a PlayerState.
	PlayerState();

	/**
	 * Announces the current state to a ResponseSink.
	 * @param sink The ResponseSink to which the current state shall be
	 *   emitted.
	 */
	void Emit(ResponseSink &sink) const override;

	/**
	 * Checks whether the current state is in a given list of states.
	 * @param states The initialiser list of states.
	 * @return True if the state is in the List; false otherwise.
	 */
	bool In(List states) const;

	/**
	 * Returns whether the player is still running.
	 * @return True if the player is not in the QUITTING state; false
	 *   otherwise.
	 */
	bool IsRunning() const;

	/**
	 * Sets the player's current state.
	 * This will automatically emit the new state to any responder that has
	 * been registered with this PlayerState using SetResponseSink.
	 * @param state The new state.
	 */
	void Set(State state);

private:
	/// A mapping between states and their human-readable names.
	const static std::map<State, std::string> STRINGS;

	/// The current state.
	State current;
};

#endif // PS_PLAYER_STATE_HPP
<commit_msg>Missed one<commit_after>// This file is part of Playslave-C++.
// Playslave-C++ is licenced under the MIT license: see LICENSE.txt.

/**
* @file
* Declaration of the PlayerState class, and associated types.
* @see player/player_state.cpp
*/

#ifndef PS_PLAYER_STATE_HPP
#define PS_PLAYER_STATE_HPP

#include <cstdint>
#include <initializer_list>
#include <functional>

#include "../io/io_response.hpp"

/**
 * An object holding and representing the current state of a Player.
 * @see Player
 * @see PlayerPosition
 */
class PlayerState : public ResponseSource {
public:
	/**
	 * Enumeration of states that the player can be in.
	 * The player is effectively a finite-state machine whose behaviour
	 * at any given time is dictated by the current state, which is
	 * represented by an instance of State.
	 */
	enum class State : std::uint8_t {
		STARTING, ///< The player has just initialised.
		EJECTED,  ///< The player has no song loaded.
		STOPPED,  ///< The player has a song loaded and not playing.
		PLAYING,  ///< The player has a song loaded and playing.
		QUITTING  ///< The player is about to terminate.
	};

	/// A list of states, used for IfIn.
	using List = std::initializer_list<State>;

	/// List of states in which the player is playing something.
	const static List AUDIO_PLAYING_STATES;

	/// List of states in which some audio is loaded.
	const static List AUDIO_LOADED_STATES;

	/// Constructs a PlayerState.
	PlayerState();

	/**
	 * Announces the current state to a ResponseSink.
	 * @param sink The ResponseSink to which the current state shall be
	 *   emitted.
	 */
	void Emit(ResponseSink &sink) const override;

	/**
	 * Checks whether the current state is in a given list of states.
	 * @param states The initialiser list of states.
	 * @return True if the state is in the List; false otherwise.
	 */
	bool In(List states) const;

	/**
	 * Returns whether the player is still running.
	 * @return True if the player is not in the QUITTING state; false
	 *   otherwise.
	 */
	bool IsRunning() const;

	/**
	 * Sets the player's current state.
	 * This will automatically emit the new state to any responder that has
	 * been registered with this PlayerState using SetResponseSink.
	 * @param state The new state.
	 */
	void Set(State state);

private:
	/// A mapping between states and their human-readable names.
	const static std::map<State, std::string> STRINGS;

	/// The current state.
	State current;
};

#endif // PS_PLAYER_STATE_HPP
<|endoftext|>


<commit_before>// Copyright (c) Burator 2014-2015
#include <QImage>
#include <QDebug>
#include <QString>
#include <QPixmap>
#include <QPainter>
#include <QVBoxLayout>
#include <QMouseEvent>

#include "ImageWidget.h"

B_BEGIN_NAMESPACE

void ImageWidget::loadImage(const QString &path) {
  this->path = path;
  image = QImage(path);
  resize(image.size());
}

void ImageWidget::showObject(const QRect &object) {
  curObjects.clear();
  curObjects << object;
  update();
}

void ImageWidget::showObjects(const QList<QRect> &objects) {
  curObjects = objects;
  update();
}

void ImageWidget::clear() {
  curObjects.clear();
  startPos = curPos = QPoint();
}

void ImageWidget::mousePressEvent(QMouseEvent *event) {
  QWidget::mousePressEvent(event);
  startPos = event->pos();
}

void ImageWidget::mouseMoveEvent(QMouseEvent *event) {
  QWidget::mouseMoveEvent(event);
  curPos = event->pos();
  update();
}

void ImageWidget::mouseReleaseEvent(QMouseEvent *event) {
  QWidget::mouseReleaseEvent(event);
  emit newObject(getCurObject());
  startPos = curPos = QPoint();
  update();
}

void ImageWidget::paintEvent(QPaintEvent *event) {
  QWidget::paintEvent(event);

  QPainter painter(this);
  painter.drawImage(QPoint(0, 0), image);

  foreach (const QRect &object, curObjects) {
    drawObject(painter, object);
  }

  if (!startPos.isNull() && !curPos.isNull()) {
    drawObject(painter, getCurObject());
  }
}

QRect ImageWidget::getCurObject() const {
  int x = startPos.x(), y = startPos.y(),
    x2 = curPos.x(), y2 = curPos.y();
  if (x2 < x) qSwap(x, x2);
  if (y2 < y) qSwap(y, y2);
  return QRect(x, y, x2 - x, y2 - y);
}

void ImageWidget::drawObject(QPainter &painter, const QRect &object) {
  QPen pen = painter.pen();
  pen.setWidth(2);
  pen.setColor(Qt::red);
  painter.setPen(pen);
  painter.drawRect(object);
}

B_END_NAMESPACE
<commit_msg>Only add object if set and with size > 0x0.<commit_after>// Copyright (c) Burator 2014-2015
#include <QImage>
#include <QDebug>
#include <QString>
#include <QPixmap>
#include <QPainter>
#include <QVBoxLayout>
#include <QMouseEvent>

#include "ImageWidget.h"

B_BEGIN_NAMESPACE

void ImageWidget::loadImage(const QString &path) {
  this->path = path;
  image = QImage(path);
  resize(image.size());
}

void ImageWidget::showObject(const QRect &object) {
  curObjects.clear();
  curObjects << object;
  update();
}

void ImageWidget::showObjects(const QList<QRect> &objects) {
  curObjects = objects;
  update();
}

void ImageWidget::clear() {
  curObjects.clear();
  startPos = curPos = QPoint();
}

void ImageWidget::mousePressEvent(QMouseEvent *event) {
  QWidget::mousePressEvent(event);
  startPos = event->pos();
}

void ImageWidget::mouseMoveEvent(QMouseEvent *event) {
  QWidget::mouseMoveEvent(event);
  curPos = event->pos();
  update();
}

void ImageWidget::mouseReleaseEvent(QMouseEvent *event) {
  QWidget::mouseReleaseEvent(event);
  if (!startPos.isNull() && !curPos.isNull() && startPos != curPos) {
    emit newObject(getCurObject());
  }
  startPos = curPos = QPoint();
  update();
}

void ImageWidget::paintEvent(QPaintEvent *event) {
  QWidget::paintEvent(event);

  QPainter painter(this);
  painter.drawImage(QPoint(0, 0), image);

  foreach (const QRect &object, curObjects) {
    drawObject(painter, object);
  }

  if (!startPos.isNull() && !curPos.isNull()) {
    drawObject(painter, getCurObject());
  }
}

QRect ImageWidget::getCurObject() const {
  int x = startPos.x(), y = startPos.y(),
    x2 = curPos.x(), y2 = curPos.y();
  if (x2 < x) qSwap(x, x2);
  if (y2 < y) qSwap(y, y2);
  return QRect(x, y, x2 - x, y2 - y);
}

void ImageWidget::drawObject(QPainter &painter, const QRect &object) {
  QPen pen = painter.pen();
  pen.setWidth(2);
  pen.setColor(Qt::red);
  painter.setPen(pen);
  painter.drawRect(object);
}

B_END_NAMESPACE
<|endoftext|>


<commit_before>#include "audiere.h"
#include "internal.h"

namespace audiere {

  ADR_EXPORT(const char*, AdrGetVersion)() {
    return "1.2.0 " __DATE__ " " __TIME__;
  }

}
<commit_msg>more informative version string<commit_after>#include "audiere.h"
#include "internal.h"

namespace audiere {

  ADR_EXPORT(const char*, AdrGetVersion)() {
    return "Audiere 1.2.0 - " __DATE__ " - " __TIME__;
  }

}
<|endoftext|>


<commit_before>#include "actions.h"
#include "../render/render.h"
#include "../render/html/page.h"
#include "../render/http.h"
#include "../render/json.h"
#include "../session.h"
#include "../number.h"
#include "../path.h"
#include "../log.h"
#include "../track.h"
#include "../user.h"
#include "../cgi.h"
#include "../media.h"
#include <string.h>
#include <fstream>
#include <taglib/mpegfile.h>
#include <taglib/tag.h>
#include <sys/stat.h>
#include <unistd.h>

using namespace Render;
using namespace Json;

std::string getTitle(const char *filename){
    TagLib::MPEG::File f(filename);
    TagLib::Tag *t = f.tag();
    return t? t->title().to8Bit(): "";
}

void Action::uploadTrack(int id){
    User u = Session::user();
    if(!u) return Http::redirect(Track::url(id));

    cgicc::file_iterator qqfile = cgi.getFile("qqfile");
    bool js = cgi("js") != "no";
    std::string upfilename = (qqfile != cgi.getFiles().end() ? qqfile->getFilename() : cgi("qqfile"));

    if(js) Http::header("text/html"); // Opera

    Track t(id);
    if((t && t.artist() != u) || upfilename.empty()){
        if(js) o << "{" << field("success","false",true) << "}";
        else Http::redirect(t ? t.url() : u ? u.url() : "/");
        return;
    }

    std::string::size_type ext_idx = upfilename.rfind('.');
    std::string ext = (ext_idx == std::string::npos ? std::string() : upfilename.substr(ext_idx));

    std::string dir = eqbeatsDir() + "/tmp";
    char *tmpFile = tempnam(dir.c_str(), "eqb");
    if(!ext.empty()){
        tmpFile = (char*) realloc(tmpFile, strlen(tmpFile) + ext.size() + 1);
        strcat(tmpFile, ext.c_str());
    }

    std::ofstream out(tmpFile, std::ios_base::binary);
    if(qqfile != cgi.getFiles().end())
        qqfile->writeToStream(out);
    else if(js)
        out << cgi.getEnvironment().getPostData();
    out.close();

    if(id == -1){
        std::string title = getTitle(tmpFile);
        if(title.empty())
            title = upfilename.substr(0, ext_idx);
        t = Track::create(u.id(), title.empty()? "Untitled":title);
    }

    log("Track uploaded: " + t.title() + " (" + number(t.id()) + ")");

    Media m(t);
    if(fork() == 0){
        freopen("/dev/null","r",stdin);
        execlp("transcode.sh", "transcode.sh", number(m.id()).c_str(), tmpFile, u.name().c_str(), t.title().c_str(), NULL);
        free(tmpFile);
    }
    else
        sleep(1);

    if(js)
        o << "{"+field("success","true")+field("track",number(t.id()))+field("title",jstring(t.title()),true)+"}";
    else Http::redirect(t.url());
}

void Action::newTrack(){
    uploadTrack(-1);
}
<commit_msg>audio file: default extension<commit_after>#include "actions.h"
#include "../render/render.h"
#include "../render/html/page.h"
#include "../render/http.h"
#include "../render/json.h"
#include "../session.h"
#include "../number.h"
#include "../path.h"
#include "../log.h"
#include "../track.h"
#include "../user.h"
#include "../cgi.h"
#include "../media.h"
#include <string.h>
#include <fstream>
#include <taglib/mpegfile.h>
#include <taglib/tag.h>
#include <sys/stat.h>
#include <unistd.h>

using namespace Render;
using namespace Json;

std::string getTitle(const char *filename){
    TagLib::MPEG::File f(filename);
    TagLib::Tag *t = f.tag();
    return t? t->title().to8Bit(): "";
}

void Action::uploadTrack(int id){
    User u = Session::user();
    if(!u) return Http::redirect(Track::url(id));

    cgicc::file_iterator qqfile = cgi.getFile("qqfile");
    bool js = cgi("js") != "no";
    std::string upfilename = (qqfile != cgi.getFiles().end() ? qqfile->getFilename() : cgi("qqfile"));

    if(js) Http::header("text/html"); // Opera

    Track t(id);
    if((t && t.artist() != u) || upfilename.empty()){
        if(js) o << "{" << field("success","false",true) << "}";
        else Http::redirect(t ? t.url() : u ? u.url() : "/");
        return;
    }

    std::string::size_type ext_idx = upfilename.rfind('.');
    std::string ext = (ext_idx == std::string::npos ? ".derp" : upfilename.substr(ext_idx));

    std::string dir = eqbeatsDir() + "/tmp";
    char *tmpFile = tempnam(dir.c_str(), "eqb");
    tmpFile = (char*) realloc(tmpFile, strlen(tmpFile) + ext.size() + 1);
    strcat(tmpFile, ext.c_str());

    std::ofstream out(tmpFile, std::ios_base::binary);
    if(qqfile != cgi.getFiles().end())
        qqfile->writeToStream(out);
    else if(js)
        out << cgi.getEnvironment().getPostData();
    out.close();

    if(id == -1){
        std::string title = getTitle(tmpFile);
        if(title.empty())
            title = upfilename.substr(0, ext_idx);
        t = Track::create(u.id(), title.empty()? "Untitled":title);
    }

    log("Track uploaded: " + t.title() + " (" + number(t.id()) + ")");

    Media m(t);
    if(fork() == 0){
        freopen("/dev/null","r",stdin);
        execlp("transcode.sh", "transcode.sh", number(m.id()).c_str(), tmpFile, u.name().c_str(), t.title().c_str(), NULL);
        free(tmpFile);
    }
    else
        sleep(2);

    if(js)
        o << "{"+field("success","true")+field("track",number(t.id()))+field("title",jstring(t.title()),true)+"}";
    else Http::redirect(t.url());
}

void Action::newTrack(){
    uploadTrack(-1);
}
<|endoftext|>