<commit_before>#include "Manager.h"
#include "Util.h"
#include "SearchCubePruning.h"
#include "StaticData.h"
#include "InputType.h"
#include "TranslationOptionCollection.h"
#include <boost/foreach.hpp>
using namespace std;

namespace Moses
{
class BitmapContainerOrderer
{
public:
  bool operator()(const BitmapContainer* A, const BitmapContainer* B) const {
    if (B->Empty()) {
      if (A->Empty()) {
        return A < B;
      }
      return false;
    }
    if (A->Empty()) {
      return true;
    }

    // Compare the top hypothesis of each bitmap container using the TotalScore, which includes future cost
    const float scoreA = A->Top()->GetHypothesis()->GetTotalScore();
    const float scoreB = B->Top()->GetHypothesis()->GetTotalScore();

    if (scoreA < scoreB) {
      return true;
    } else if (scoreA > scoreB) {
      return false;
    } else {
      return A < B;
    }
  }
};

SearchCubePruning::
SearchCubePruning(Manager& manager, const InputType &source,
		  const TranslationOptionCollection &transOptColl)
  : Search(manager)
  , m_source(source)
  , m_hypoStackColl(source.GetSize() + 1)
  , m_transOptColl(transOptColl)
{
  const StaticData &staticData = StaticData::Instance();

  std::vector < HypothesisStackCubePruning >::iterator iterStack;
  for (size_t ind = 0 ; ind < m_hypoStackColl.size() ; ++ind) {
    HypothesisStackCubePruning *sourceHypoColl = new HypothesisStackCubePruning(m_manager);
    sourceHypoColl->SetMaxHypoStackSize(m_options.search.stack_size);
    sourceHypoColl->SetBeamWidth(m_options.search.beam_width);

    m_hypoStackColl[ind] = sourceHypoColl;
  }
}

SearchCubePruning::~SearchCubePruning()
{
  RemoveAllInColl(m_hypoStackColl);
}

/**
 * Main decoder loop that translates a sentence by expanding
 * hypotheses stack by stack, until the end of the sentence.
 */
void SearchCubePruning::Decode()
{
  const StaticData &SD = StaticData::Instance();
  AllOptions const& opts = SD.options();

  // initial seed hypothesis: nothing translated, no words produced
  Hypothesis *hypo = Hypothesis::Create(m_manager,m_source, m_initialTransOpt);

  HypothesisStackCubePruning &firstStack
    = *static_cast<HypothesisStackCubePruning*>(m_hypoStackColl.front());
  firstStack.AddInitial(hypo);
  // Call this here because the loop below starts at the second stack.
  firstStack.CleanupArcList();
  CreateForwardTodos(firstStack);

  const size_t PopLimit = StaticData::Instance().options().cube.pop_limit;
  VERBOSE(3,"Cube Pruning pop limit is " << PopLimit << std::endl);

  const size_t Diversity = StaticData::Instance().options().cube.diversity;
  VERBOSE(3,"Cube Pruning diversity is " << Diversity << std::endl)

  // go through each stack
  size_t stackNo = 1;
  int timelimit = m_options.search.timeout;
  std::vector < HypothesisStack* >::iterator iterStack;
  for (iterStack = m_hypoStackColl.begin() + 1 ; iterStack != m_hypoStackColl.end() ; ++iterStack) {
    // BOOST_FOREACH(HypothesisStack* hstack, m_hypoStackColl) {
    if (this->out_of_time()) return;

    HypothesisStackCubePruning &sourceHypoColl
      = *static_cast<HypothesisStackCubePruning*>(*iterStack);

    // priority queue which has a single entry for each bitmap
    // container, sorted by score of top hyp
    std::priority_queue < BitmapContainer*, std::vector< BitmapContainer* >,
			  BitmapContainerOrderer > BCQueue;

    _BMType::const_iterator bmIter;
    const _BMType &accessor = sourceHypoColl.GetBitmapAccessor();

    for(bmIter = accessor.begin(); bmIter != accessor.end(); ++bmIter) {
      // build the first hypotheses
      bmIter->second->InitializeEdges();
      m_manager.GetSentenceStats().StartTimeManageCubes();
      BCQueue.push(bmIter->second);
      m_manager.GetSentenceStats().StopTimeManageCubes();

      // old algorithm
      // bmIter->second->EnsureMinStackHyps(PopLimit);
    }

    // main search loop, pop k best hyps
    for (size_t numpops = 1; numpops <= PopLimit && !BCQueue.empty(); numpops++) {
      // get currently best hypothesis in queue
      m_manager.GetSentenceStats().StartTimeManageCubes();
      BitmapContainer *bc = BCQueue.top();
      BCQueue.pop();
      m_manager.GetSentenceStats().StopTimeManageCubes();
      IFVERBOSE(2) {
        m_manager.GetSentenceStats().AddPopped();
      }
      // push on stack and create successors
      bc->ProcessBestHypothesis();
      // if there are any hypothesis left in this specific container, add back to queue
      m_manager.GetSentenceStats().StartTimeManageCubes();
      if (!bc->Empty())
        BCQueue.push(bc);
      m_manager.GetSentenceStats().StopTimeManageCubes();
    }

    // ensure diversity, a minimum number of inserted hyps for each bitmap container;
    //    NOTE: diversity doesn't ensure they aren't pruned at some later point
    if (Diversity > 0) {
      for(bmIter = accessor.begin(); bmIter != accessor.end(); ++bmIter) {
        bmIter->second->EnsureMinStackHyps(Diversity);
      }
    }

    // the stack is pruned before processing (lazy pruning):
    VERBOSE(3,"processing hypothesis from next stack");
    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StartTimeStack();
    }
    sourceHypoColl.PruneToSize(m_options.search.stack_size);
    VERBOSE(3,std::endl);
    sourceHypoColl.CleanupArcList();
    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StopTimeStack();
    }

    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StartTimeSetupCubes();
    }
    CreateForwardTodos(sourceHypoColl);
    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StopTimeSetupCubes();
    }

    stackNo++;
  }
}

void SearchCubePruning::CreateForwardTodos(HypothesisStackCubePruning &stack)
{
  const _BMType &bitmapAccessor = stack.GetBitmapAccessor();
  _BMType::const_iterator iterAccessor;
  size_t size = m_source.GetSize();

  stack.AddHypothesesToBitmapContainers();

  for (iterAccessor = bitmapAccessor.begin() ; iterAccessor != bitmapAccessor.end() ; ++iterAccessor) {
    const WordsBitmap &bitmap = iterAccessor->first;
    BitmapContainer &bitmapContainer = *iterAccessor->second;

    if (bitmapContainer.GetHypothesesSize() == 0) {
      // no hypothese to expand. don't bother doing it
      continue;
    }

    // Sort the hypotheses inside the Bitmap Container as they are being used by now.
    bitmapContainer.SortHypotheses();

    // check bitamp and range doesn't overlap
    size_t startPos, endPos;
    for (startPos = 0 ; startPos < size ; startPos++) {
      if (bitmap.GetValue(startPos))
        continue;

      // not yet covered
      WordsRange applyRange(startPos, startPos);
      if (CheckDistortion(bitmap, applyRange)) {
        // apply range
        CreateForwardTodos(bitmap, applyRange, bitmapContainer);
      }

      size_t maxSize = size - startPos;
      size_t maxSizePhrase = StaticData::Instance().GetMaxPhraseLength();
      maxSize = std::min(maxSize, maxSizePhrase);

      for (endPos = startPos+1; endPos < startPos + maxSize; endPos++) {
        if (bitmap.GetValue(endPos))
          break;

        WordsRange applyRange(startPos, endPos);
        if (CheckDistortion(bitmap, applyRange)) {
          // apply range
          CreateForwardTodos(bitmap, applyRange, bitmapContainer);
        }
      }
    }
  }
}

void
SearchCubePruning::
CreateForwardTodos(WordsBitmap const& bitmap, WordsRange const& range,
                   BitmapContainer& bitmapContainer)
{
  WordsBitmap newBitmap = bitmap;
  newBitmap.SetValue(range.GetStartPos(), range.GetEndPos(), true);

  size_t numCovered = newBitmap.GetNumWordsCovered();
  const TranslationOptionList* transOptList;
  transOptList = m_transOptColl.GetTranslationOptionList(range);
  const SquareMatrix &futureScore = m_transOptColl.GetFutureScore();

  if (transOptList && transOptList->size() > 0) {
    HypothesisStackCubePruning& newStack
    = *static_cast<HypothesisStackCubePruning*>(m_hypoStackColl[numCovered]);
    newStack.SetBitmapAccessor(newBitmap, newStack, range, bitmapContainer,
                               futureScore, *transOptList);
  }
}

bool
SearchCubePruning::
CheckDistortion(const WordsBitmap &hypoBitmap, const WordsRange &range) const
{
  // since we check for reordering limits, its good to have that limit handy
  int maxDistortion = StaticData::Instance().GetMaxDistortion();
  if (maxDistortion < 0) return true;

  // if there are reordering limits, make sure it is not violated
  // the coverage bitmap is handy here (and the position of the first gap)
  size_t const startPos = range.GetStartPos();
  size_t const endPos = range.GetEndPos();

  // if reordering constraints are used (--monotone-at-punctuation or xml),
  // check if passes all
  if (!m_source.GetReorderingConstraint().Check(hypoBitmap, startPos, endPos))
    return false;

  size_t const hypoFirstGapPos = hypoBitmap.GetFirstGapPos();
  // any length extension is okay if starting at left-most edge
  if (hypoFirstGapPos == startPos) return true;

  // starting somewhere other than left-most edge, use caution
  // the basic idea is this: we would like to translate a phrase starting
  // from a position further right than the left-most open gap. The
  // distortion penalty for the following phrase will be computed relative
  // to the ending position of the current extension, so we ask now what
  // its maximum value will be (which will always be the value of the
  // hypothesis starting at the left-most edge).  If this vlaue is than
  // the distortion limit, we don't allow this extension to be made.
  WordsRange bestNextExtension(hypoFirstGapPos, hypoFirstGapPos);
  return (m_source.ComputeDistortionDistance(range, bestNextExtension)
          <= maxDistortion);
}

/**
 * Find best hypothesis on the last stack.
 * This is the end point of the best translation, which can be traced back from here
 */
Hypothesis const*
SearchCubePruning::
GetBestHypothesis() const
{
  //	const HypothesisStackCubePruning &hypoColl = m_hypoStackColl.back();
  const HypothesisStack &hypoColl = *m_hypoStackColl.back();
  return hypoColl.GetBestHypothesis();
}

/**
 * Logging of hypothesis stack sizes
 */
void
SearchCubePruning::
OutputHypoStackSize()
{
  std::vector < HypothesisStack* >::const_iterator iterStack = m_hypoStackColl.begin();
  TRACE_ERR( "Stack sizes: " << (int)(*iterStack)->size());
  for (++iterStack; iterStack != m_hypoStackColl.end() ; ++iterStack) {
    TRACE_ERR( ", " << (int)(*iterStack)->size());
  }
  TRACE_ERR( endl);
}

void SearchCubePruning::PrintBitmapContainerGraph()
{
  HypothesisStackCubePruning &lastStack = *static_cast<HypothesisStackCubePruning*>(m_hypoStackColl.back());
  const _BMType &bitmapAccessor = lastStack.GetBitmapAccessor();

  _BMType::const_iterator iterAccessor;
  for (iterAccessor = bitmapAccessor.begin(); iterAccessor != bitmapAccessor.end(); ++iterAccessor) {
    cerr << iterAccessor->first << endl;
    //BitmapContainer &container = *iterAccessor->second;
  }

}

/**
 * Logging of hypothesis stack contents
 * \param stack number of stack to be reported, report all stacks if 0
 */
void SearchCubePruning::OutputHypoStack(int stack)
{
  if (stack >= 0) {
    TRACE_ERR( "Stack " << stack << ": " << endl << m_hypoStackColl[stack] << endl);
  } else {
    // all stacks
    int i = 0;
    vector < HypothesisStack* >::iterator iterStack;
    for (iterStack = m_hypoStackColl.begin() ; iterStack != m_hypoStackColl.end() ; ++iterStack) {
      HypothesisStackCubePruning &hypoColl = *static_cast<HypothesisStackCubePruning*>(*iterStack);
      TRACE_ERR( "Stack " << i++ << ": " << endl << hypoColl << endl);
    }
  }
}

const std::vector < HypothesisStack* >& SearchCubePruning::GetHypothesisStacks() const
{
  return m_hypoStackColl;
}

}

<commit_msg>Get options from Manager instead of StaticData.<commit_after>#include "Manager.h"
#include "Util.h"
#include "SearchCubePruning.h"
#include "StaticData.h"
#include "InputType.h"
#include "TranslationOptionCollection.h"
#include <boost/foreach.hpp>
using namespace std;

namespace Moses
{
class BitmapContainerOrderer
{
public:
  bool operator()(const BitmapContainer* A, const BitmapContainer* B) const {
    if (B->Empty()) {
      if (A->Empty()) {
        return A < B;
      }
      return false;
    }
    if (A->Empty()) {
      return true;
    }

    // Compare the top hypothesis of each bitmap container using the TotalScore, which includes future cost
    const float scoreA = A->Top()->GetHypothesis()->GetTotalScore();
    const float scoreB = B->Top()->GetHypothesis()->GetTotalScore();

    if (scoreA < scoreB) {
      return true;
    } else if (scoreA > scoreB) {
      return false;
    } else {
      return A < B;
    }
  }
};

SearchCubePruning::
SearchCubePruning(Manager& manager, const InputType &source,
		  const TranslationOptionCollection &transOptColl)
  : Search(manager)
  , m_source(source)
  , m_hypoStackColl(source.GetSize() + 1)
  , m_transOptColl(transOptColl)
{
  std::vector < HypothesisStackCubePruning >::iterator iterStack;
  for (size_t ind = 0 ; ind < m_hypoStackColl.size() ; ++ind) {
    HypothesisStackCubePruning *sourceHypoColl = new HypothesisStackCubePruning(m_manager);
    sourceHypoColl->SetMaxHypoStackSize(m_options.search.stack_size);
    sourceHypoColl->SetBeamWidth(m_options.search.beam_width);

    m_hypoStackColl[ind] = sourceHypoColl;
  }
}

SearchCubePruning::~SearchCubePruning()
{
  RemoveAllInColl(m_hypoStackColl);
}

/**
 * Main decoder loop that translates a sentence by expanding
 * hypotheses stack by stack, until the end of the sentence.
 */
void SearchCubePruning::Decode()
{
  // initial seed hypothesis: nothing translated, no words produced
  Hypothesis *hypo = Hypothesis::Create(m_manager,m_source, m_initialTransOpt);

  HypothesisStackCubePruning &firstStack
    = *static_cast<HypothesisStackCubePruning*>(m_hypoStackColl.front());
  firstStack.AddInitial(hypo);
  // Call this here because the loop below starts at the second stack.
  firstStack.CleanupArcList();
  CreateForwardTodos(firstStack);

  const size_t PopLimit = m_manager.options().cube.pop_limit;
  VERBOSE(2,"Cube Pruning pop limit is " << PopLimit << std::endl);

  const size_t Diversity = m_manager.options().cube.diversity;
  VERBOSE(2,"Cube Pruning diversity is " << Diversity << std::endl);
  VERBOSE(2,"Max Phrase length is "
	  << m_manager.options().search.max_phrase_length << std::endl);

  // go through each stack
  size_t stackNo = 1;
  int timelimit = m_options.search.timeout;
  std::vector < HypothesisStack* >::iterator iterStack;
  for (iterStack = m_hypoStackColl.begin() + 1 ; iterStack != m_hypoStackColl.end() ; ++iterStack) {
    // BOOST_FOREACH(HypothesisStack* hstack, m_hypoStackColl) {
    if (this->out_of_time()) return;

    HypothesisStackCubePruning &sourceHypoColl
      = *static_cast<HypothesisStackCubePruning*>(*iterStack);

    // priority queue which has a single entry for each bitmap
    // container, sorted by score of top hyp
    std::priority_queue < BitmapContainer*, std::vector< BitmapContainer* >,
			  BitmapContainerOrderer > BCQueue;

    _BMType::const_iterator bmIter;
    const _BMType &accessor = sourceHypoColl.GetBitmapAccessor();

    for(bmIter = accessor.begin(); bmIter != accessor.end(); ++bmIter) {
      // build the first hypotheses
      bmIter->second->InitializeEdges();
      m_manager.GetSentenceStats().StartTimeManageCubes();
      BCQueue.push(bmIter->second);
      m_manager.GetSentenceStats().StopTimeManageCubes();

      // old algorithm
      // bmIter->second->EnsureMinStackHyps(PopLimit);
    }

    // main search loop, pop k best hyps
    for (size_t numpops = 1; numpops <= PopLimit && !BCQueue.empty(); numpops++) {
      // get currently best hypothesis in queue
      m_manager.GetSentenceStats().StartTimeManageCubes();
      BitmapContainer *bc = BCQueue.top();
      BCQueue.pop();
      m_manager.GetSentenceStats().StopTimeManageCubes();
      IFVERBOSE(2) {
        m_manager.GetSentenceStats().AddPopped();
      }
      // push on stack and create successors
      bc->ProcessBestHypothesis();
      // if there are any hypothesis left in this specific container, add back to queue
      m_manager.GetSentenceStats().StartTimeManageCubes();
      if (!bc->Empty())
        BCQueue.push(bc);
      m_manager.GetSentenceStats().StopTimeManageCubes();
    }

    // ensure diversity, a minimum number of inserted hyps for each bitmap container;
    //    NOTE: diversity doesn't ensure they aren't pruned at some later point
    if (Diversity > 0) {
      for(bmIter = accessor.begin(); bmIter != accessor.end(); ++bmIter) {
        bmIter->second->EnsureMinStackHyps(Diversity);
      }
    }

    // the stack is pruned before processing (lazy pruning):
    VERBOSE(3,"processing hypothesis from next stack");
    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StartTimeStack();
    }
    sourceHypoColl.PruneToSize(m_options.search.stack_size);
    VERBOSE(3,std::endl);
    sourceHypoColl.CleanupArcList();
    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StopTimeStack();
    }

    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StartTimeSetupCubes();
    }
    CreateForwardTodos(sourceHypoColl);
    IFVERBOSE(2) {
      m_manager.GetSentenceStats().StopTimeSetupCubes();
    }

    stackNo++;
  }
}

void SearchCubePruning::CreateForwardTodos(HypothesisStackCubePruning &stack)
{
  const _BMType &bitmapAccessor = stack.GetBitmapAccessor();
  _BMType::const_iterator iterAccessor;
  size_t size = m_source.GetSize();

  stack.AddHypothesesToBitmapContainers();

  for (iterAccessor = bitmapAccessor.begin() ; iterAccessor != bitmapAccessor.end() ; ++iterAccessor) {
    const WordsBitmap &bitmap = iterAccessor->first;
    BitmapContainer &bitmapContainer = *iterAccessor->second;

    if (bitmapContainer.GetHypothesesSize() == 0) {
      // no hypothese to expand. don't bother doing it
      continue;
    }

    // Sort the hypotheses inside the Bitmap Container as they are being used by now.
    bitmapContainer.SortHypotheses();

    // check bitamp and range doesn't overlap
    size_t startPos, endPos;
    for (startPos = 0 ; startPos < size ; startPos++) {
      if (bitmap.GetValue(startPos))
        continue;

      // not yet covered
      WordsRange applyRange(startPos, startPos);
      if (CheckDistortion(bitmap, applyRange)) {
        // apply range
        CreateForwardTodos(bitmap, applyRange, bitmapContainer);
      }

      size_t maxSize = size - startPos;
      size_t maxSizePhrase = m_manager.options().search.max_phrase_length;
      maxSize = std::min(maxSize, maxSizePhrase);

      for (endPos = startPos+1; endPos < startPos + maxSize; endPos++) {
        if (bitmap.GetValue(endPos))
          break;

        WordsRange applyRange(startPos, endPos);
        if (CheckDistortion(bitmap, applyRange)) {
          // apply range
          CreateForwardTodos(bitmap, applyRange, bitmapContainer);
        }
      }
    }
  }
}

void
SearchCubePruning::
CreateForwardTodos(WordsBitmap const& bitmap, WordsRange const& range,
                   BitmapContainer& bitmapContainer)
{
  WordsBitmap newBitmap = bitmap;
  newBitmap.SetValue(range.GetStartPos(), range.GetEndPos(), true);

  size_t numCovered = newBitmap.GetNumWordsCovered();
  const TranslationOptionList* transOptList;
  transOptList = m_transOptColl.GetTranslationOptionList(range);
  const SquareMatrix &futureScore = m_transOptColl.GetFutureScore();

  if (transOptList && transOptList->size() > 0) {
    HypothesisStackCubePruning& newStack
    = *static_cast<HypothesisStackCubePruning*>(m_hypoStackColl[numCovered]);
    newStack.SetBitmapAccessor(newBitmap, newStack, range, bitmapContainer,
                               futureScore, *transOptList);
  }
}

bool
SearchCubePruning::
CheckDistortion(const WordsBitmap &hypoBitmap, const WordsRange &range) const
{
  // since we check for reordering limits, its good to have that limit handy
  int maxDistortion = m_manager.options().reordering.max_distortion;
  if (maxDistortion < 0) return true;

  // if there are reordering limits, make sure it is not violated
  // the coverage bitmap is handy here (and the position of the first gap)
  size_t const startPos = range.GetStartPos();
  size_t const endPos = range.GetEndPos();

  // if reordering constraints are used (--monotone-at-punctuation or xml),
  // check if passes all
  if (!m_source.GetReorderingConstraint().Check(hypoBitmap, startPos, endPos))
    return false;

  size_t const hypoFirstGapPos = hypoBitmap.GetFirstGapPos();
  // any length extension is okay if starting at left-most edge
  if (hypoFirstGapPos == startPos) return true;

  // starting somewhere other than left-most edge, use caution
  // the basic idea is this: we would like to translate a phrase starting
  // from a position further right than the left-most open gap. The
  // distortion penalty for the following phrase will be computed relative
  // to the ending position of the current extension, so we ask now what
  // its maximum value will be (which will always be the value of the
  // hypothesis starting at the left-most edge).  If this vlaue is than
  // the distortion limit, we don't allow this extension to be made.
  WordsRange bestNextExtension(hypoFirstGapPos, hypoFirstGapPos);
  return (m_source.ComputeDistortionDistance(range, bestNextExtension)
          <= maxDistortion);
}

/**
 * Find best hypothesis on the last stack.
 * This is the end point of the best translation, which can be traced back from here
 */
Hypothesis const*
SearchCubePruning::
GetBestHypothesis() const
{
  //	const HypothesisStackCubePruning &hypoColl = m_hypoStackColl.back();
  const HypothesisStack &hypoColl = *m_hypoStackColl.back();
  return hypoColl.GetBestHypothesis();
}

/**
 * Logging of hypothesis stack sizes
 */
void
SearchCubePruning::
OutputHypoStackSize()
{
  std::vector < HypothesisStack* >::const_iterator iterStack = m_hypoStackColl.begin();
  TRACE_ERR( "Stack sizes: " << (int)(*iterStack)->size());
  for (++iterStack; iterStack != m_hypoStackColl.end() ; ++iterStack) {
    TRACE_ERR( ", " << (int)(*iterStack)->size());
  }
  TRACE_ERR( endl);
}

void SearchCubePruning::PrintBitmapContainerGraph()
{
  HypothesisStackCubePruning &lastStack = *static_cast<HypothesisStackCubePruning*>(m_hypoStackColl.back());
  const _BMType &bitmapAccessor = lastStack.GetBitmapAccessor();

  _BMType::const_iterator iterAccessor;
  for (iterAccessor = bitmapAccessor.begin(); iterAccessor != bitmapAccessor.end(); ++iterAccessor) {
    cerr << iterAccessor->first << endl;
    //BitmapContainer &container = *iterAccessor->second;
  }

}

/**
 * Logging of hypothesis stack contents
 * \param stack number of stack to be reported, report all stacks if 0
 */
void SearchCubePruning::OutputHypoStack(int stack)
{
  if (stack >= 0) {
    TRACE_ERR( "Stack " << stack << ": " << endl << m_hypoStackColl[stack] << endl);
  } else {
    // all stacks
    int i = 0;
    vector < HypothesisStack* >::iterator iterStack;
    for (iterStack = m_hypoStackColl.begin() ; iterStack != m_hypoStackColl.end() ; ++iterStack) {
      HypothesisStackCubePruning &hypoColl = *static_cast<HypothesisStackCubePruning*>(*iterStack);
      TRACE_ERR( "Stack " << i++ << ": " << endl << hypoColl << endl);
    }
  }
}

const std::vector < HypothesisStack* >& SearchCubePruning::GetHypothesisStacks() const
{
  return m_hypoStackColl;
}

}

<|endoftext|>


<commit_before>#include <mu_coin_qt/qt.hpp>

#include <thread>

int main (int argc, char ** argv)
{
    QApplication application (argc, argv);
    auto service (boost::make_shared <boost::asio::io_service> ());
    auto pool (boost::make_shared <boost::network::utils::thread_pool> ());
    mu_coin::processor_service processor;
    auto client (std::make_shared <mu_coin::client> (service, pool, 24000, 25000, boost::filesystem::system_complete (argv[0]).parent_path () / "data", processor, ));
    std::unique_ptr <mu_coin_qt::gui> (new mu_coin_qt::gui (application, *client))
    std::thread network_thread ([&system] ()
    {
        try
        {
            service->run ();
        }
        catch (...)
        {
            assert (false);
        }
        std::cerr << "Network thread exited" << std::endl;
    });
    std::thread processor_thread ([&system] ()
    {
        try
        {
            processor.run ();
        }
        catch (...)
        {
            assert (false);
        }
        std::cerr << "Processor thread exited" << std::endl;
    });
    QObject::connect (&application, &QApplication::aboutToQuit, [&] ()
    {
        client->stop ();
    });
    int result;
    try
    {
        result = application.exec ();
    }
    catch (...)
    {
        result = -1;
        assert (false);
    }
    network_thread.join ();
    processor_thread.join ();
    return result;
}<commit_msg>Getting single client working.<commit_after>#include <mu_coin_qt/qt.hpp>

#include <thread>

int main (int argc, char ** argv)
{
    QApplication application (argc, argv);
    auto service (boost::make_shared <boost::asio::io_service> ());
    auto pool (boost::make_shared <boost::network::utils::thread_pool> ());
    mu_coin::processor_service processor;
    auto client (std::make_shared <mu_coin::client> (service, pool, 24000, 25000, boost::filesystem::system_complete (argv[0]).parent_path () / "data", processor, mu_coin::genesis_address));
    std::unique_ptr <mu_coin_qt::gui> gui (new mu_coin_qt::gui (application, *client));
	gui->client_window->show ();
    std::thread network_thread ([&service] ()
    {
        try
        {
            service->run ();
        }
        catch (...)
        {
            assert (false);
        }
        std::cerr << "Network thread exited" << std::endl;
    });
    std::thread processor_thread ([&processor] ()
    {
        try
        {
            processor.run ();
        }
        catch (...)
        {
            assert (false);
        }
        std::cerr << "Processor thread exited" << std::endl;
    });
    QObject::connect (&application, &QApplication::aboutToQuit, [&] ()
    {
        client->stop ();
    });
    int result;
    try
    {
        result = application.exec ();
    }
    catch (...)
    {
        result = -1;
        assert (false);
    }
    network_thread.join ();
    processor_thread.join ();
    return result;
}<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <multimedia/qradioplayer.h>
#include <multimedia/qmediaservice.h>
#include <multimedia/qmediaobject_p.h>
#include <multimedia/qradioplayercontrol.h>

/*!
    \class QRadioPlayer
    \brief The QRadioPlayer class provides an interface to the systems radio device.

    You can control the systems radio device using this interface, for example:

    \code
        player = new QRadioPlayer;
        connect(player,SIGNAL(frequencyChanged(int)),this,SLOT(freqChanged(int)));
        if(player->isSupportedBand(QRadioPlayer::FM))
            player->setBand(QRadioPlayer::FM);
        player->setFrequency(yourRadioStationFrequency);
        player->setVolume(100);
    \endcode

    The player object will emit signals for any changes in state such as:
    bandChanged(), frequencyChanged(), stereoStatusChanged(), searchingStatusChanged(),
    signalStrengthChanged(), durationChanged(), volumeChanged(), mutingChanged().

    You can change between the frequency bands using setBand() however it is recommended
    that you check to make sure the band is available first using isSupportedBand().

*/

class QRadioPlayerPrivate : public QMediaObjectPrivate
{
public:
    QRadioPlayerPrivate():service(0), control(0) {}
    QMediaService*  service;
    QRadioPlayerControl* control;
    bool ownService;
};

/*!
    Construct a QRadioPlayer object with service \a provider and \a parent.

    If the service is not specified the system default will be used.
*/

QRadioPlayer::QRadioPlayer(QObject *parent, QMediaServiceProvider* provider):
    QMediaObject(*new QRadioPlayerPrivate, parent, provider->requestService("radio"))
{
    Q_D(QRadioPlayer);

    Q_ASSERT(d->service != 0);

    if (d->service != 0) {
        d->control = qobject_cast<QRadioPlayerControl*>(d->service->control(QRadioPlayerControl_iid));
        if (d->control != 0) {
            connect(d->control, SIGNAL(bandChanged(QRadioPlayer::Band)), SIGNAL(bandChanged(QRadioPlayer::Band)));
            connect(d->control, SIGNAL(frequencyChanged(int)), SIGNAL(frequencyChanged(int)));
            connect(d->control, SIGNAL(stereoStatusChanged(bool)), SIGNAL(stereoStatusChanged(bool)));
            connect(d->control, SIGNAL(searchingStatusChanged(bool)), SIGNAL(searchingStatusChanged(bool)));
            connect(d->control, SIGNAL(signalStrengthChanged(int)), SIGNAL(signalStrengthChanged(int)));
            connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64)));
            connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int)));
            connect(d->control, SIGNAL(mutingChanged(bool)), SIGNAL(mutingChanged(bool)));

            addPropertyWatch("duration");
        }
    }
}

/*!
    Destruct the QRadioPlayer object.
*/

QRadioPlayer::~QRadioPlayer()
{
}

/*!
    \property QRadioPlayer::band
    \brief The current frequency range being used.

    \sa QRadioPlayer::Band
*/

/*!
    Returns the current QRadioPlayer::Band.
*/

QRadioPlayer::Band QRadioPlayer::band() const
{
    return QRadioPlayer::Band(d_func()->control->band());
}

/*!
    \property QRadioPlayer::frequency
    \brief The current frequency being used in Hertz.
*/

/*!
    Returns the current frequency.
*/

int QRadioPlayer::frequency() const
{
    return d_func()->control->frequency();
}

/*!
    \property QRadioPlayer::stereo
    \brief In Stereo mode.
*/

/*!
    Returns true if in stereo.
*/

bool QRadioPlayer::isStereo() const
{
    return d_func()->control->isStereo();
}

/*!
    Returns true if \a b is an available band.
*/

bool QRadioPlayer::isSupportedBand(QRadioPlayer::Band b) const
{
    return d_func()->control->isSupportedBand(b);
}

/*!
    \property QRadioPlayer::signalStrength
    \brief The strength of the current radio signal as a percentage.
*/

/*!
    Returns the signal strength as a percentage.
*/

int QRadioPlayer::signalStrength() const
{
    return d_func()->control->signalStrength();
}

/*!
    \property QRadioPlayer::duration
    \brief The duration at current frequency in milliseconds.
*/

/*!
    Returns duration at current frequency in milliseconds.
*/

qint64 QRadioPlayer::duration() const
{
    return d_func()->control->duration();
}

/*!
    \property QRadioPlayer::volume
    \brief The current volume as a percentage.
*/

/*!
    Returns the volume as a percentage.
*/

int QRadioPlayer::volume() const
{
    return d_func()->control->volume();
}

/*!
    \property QRadioPlayer::muted
    \brief Returns true if muted.
*/

/*!
    Returns true if muted.
*/

bool QRadioPlayer::isMuted() const
{
    return d_func()->control->isMuted();
}

/*!
    Sets the band being used to \a band.
*/

void QRadioPlayer::setBand(QRadioPlayer::Band band)
{
    d_func()->control->setBand(band);
}

/*!
    Sets the frequency being used to \a frequency.
*/

void QRadioPlayer::setFrequency(int frequency)
{
    d_func()->control->setFrequency(frequency);
}

/*!
    If \a stereo is true, Sets to stereo mode, otherwise, mono mode.
*/

void QRadioPlayer::setStereo(bool stereo)
{
    d_func()->control->setStereo(stereo);
}

/*!
    Sets the volume to \a volume.
    volume is a percentage.
*/

void QRadioPlayer::setVolume(int volume)
{
    d_func()->control->setVolume(volume);
}

/*!
    If muted is true sets to mute, otherwise unmute.
*/

void QRadioPlayer::setMuted(bool muted)
{
    d_func()->control->setMuted(muted);
}

/*!
    Returns true if an available device.
*/

bool QRadioPlayer::isValid() const
{
    return QMediaObject::isValid() && d_func()->control != 0;
}

/*!
    \property QRadioPlayer::searching
    \brief Returns true if currently scanning.
*/

/*!
    Returns true if currently scanning.
*/

bool QRadioPlayer::isSearching() const
{
    return d_func()->control->isSearching();
}

/*!
    Start scanning through frequencies, ascending.
*/

void QRadioPlayer::searchForward()
{
    d_func()->control->searchForward();
}

/*!
    Start scanning through frequencies, descending.
*/

void QRadioPlayer::searchBackward()
{
    d_func()->control->searchBackward();
}

/*!
    Stop any scanning being done.
*/

void QRadioPlayer::cancelSearch()
{
    d_func()->control->cancelSearch();
}

/*!
    \fn void QRadioPlayer::bandChanged(QRadioPlayer::Band band)

    Signal the change in frequency range to \a band.
*/

/*!
    \fn void QRadioPlayer::frequencyChanged(int frequency)

    Signal the change in current \a frequency.
*/

/*!
    \fn void QRadioPlayer::mutingChanged(bool muted)

    Signal the change in mute condition to \a muted.
*/

/*!
    \fn void QRadioPlayer::volumeChanged(int volume)

    Signal the change in volume percentage to \a volume.
*/

/*!
    \fn void QRadioPlayer::searchingStatusChanged(bool searching)

    Signal the change in scanning mode to \a searching.
*/

/*!
    \fn void QRadioPlayer::stereoStatusChanged(bool stereo)

    Signal the change in stereo mode to \a stereo.
*/

/*!
    \fn void QRadioPlayer::durationChanged(qint64 duration)

    Signal the change in the \a duration of the current frequency playback in milliseconds.
*/

/*!
    \fn void QRadioPlayer::signalStrengthChanged(int signalStrength)

    Signal emitted when signal strength changes to new value \a signalStrength.
*/

/*!
    \enum QRadioPlayer::Band

    \value AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz
    \value FM 87.5 to 108.0 MHz, except Japan 76-90 MHz
    \value SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing
    \value LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia)
*/

<commit_msg>QRadioPlayer; Use base service, release on destruct.<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at http://qt.nokia.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <multimedia/qradioplayer.h>
#include <multimedia/qmediaservice.h>
#include <multimedia/qmediaobject_p.h>
#include <multimedia/qradioplayercontrol.h>

/*!
    \class QRadioPlayer
    \brief The QRadioPlayer class provides an interface to the systems radio device.

    You can control the systems radio device using this interface, for example:

    \code
        player = new QRadioPlayer;
        connect(player,SIGNAL(frequencyChanged(int)),this,SLOT(freqChanged(int)));
        if(player->isSupportedBand(QRadioPlayer::FM))
            player->setBand(QRadioPlayer::FM);
        player->setFrequency(yourRadioStationFrequency);
        player->setVolume(100);
    \endcode

    The player object will emit signals for any changes in state such as:
    bandChanged(), frequencyChanged(), stereoStatusChanged(), searchingStatusChanged(),
    signalStrengthChanged(), durationChanged(), volumeChanged(), mutingChanged().

    You can change between the frequency bands using setBand() however it is recommended
    that you check to make sure the band is available first using isSupportedBand().

*/

class QRadioPlayerPrivate : public QMediaObjectPrivate
{
public:
    QRadioPlayerPrivate():provider(0), control(0) {}
    QMediaServiceProvider *provider;
    QRadioPlayerControl* control;
};

/*!
    Construct a QRadioPlayer object with service \a provider and \a parent.

    If the service is not specified the system default will be used.
*/

QRadioPlayer::QRadioPlayer(QObject *parent, QMediaServiceProvider* provider):
    QMediaObject(*new QRadioPlayerPrivate, parent, provider->requestService("radio"))
{
    Q_D(QRadioPlayer);

    d->provider = provider;

    Q_ASSERT(d->service != 0);

    if (d->service != 0) {
        d->control = qobject_cast<QRadioPlayerControl*>(d->service->control(QRadioPlayerControl_iid));
        if (d->control != 0) {
            connect(d->control, SIGNAL(bandChanged(QRadioPlayer::Band)), SIGNAL(bandChanged(QRadioPlayer::Band)));
            connect(d->control, SIGNAL(frequencyChanged(int)), SIGNAL(frequencyChanged(int)));
            connect(d->control, SIGNAL(stereoStatusChanged(bool)), SIGNAL(stereoStatusChanged(bool)));
            connect(d->control, SIGNAL(searchingStatusChanged(bool)), SIGNAL(searchingStatusChanged(bool)));
            connect(d->control, SIGNAL(signalStrengthChanged(int)), SIGNAL(signalStrengthChanged(int)));
            connect(d->control, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64)));
            connect(d->control, SIGNAL(volumeChanged(int)), SIGNAL(volumeChanged(int)));
            connect(d->control, SIGNAL(mutingChanged(bool)), SIGNAL(mutingChanged(bool)));

            addPropertyWatch("duration");
        }
    }
}

/*!
    Destruct the QRadioPlayer object.
*/

QRadioPlayer::~QRadioPlayer()
{
    Q_D(QRadioPlayer);

    d->provider->releaseService(d->service);
}

/*!
    \property QRadioPlayer::band
    \brief The current frequency range being used.

    \sa QRadioPlayer::Band
*/

/*!
    Returns the current QRadioPlayer::Band.
*/

QRadioPlayer::Band QRadioPlayer::band() const
{
    return QRadioPlayer::Band(d_func()->control->band());
}

/*!
    \property QRadioPlayer::frequency
    \brief The current frequency being used in Hertz.
*/

/*!
    Returns the current frequency.
*/

int QRadioPlayer::frequency() const
{
    return d_func()->control->frequency();
}

/*!
    \property QRadioPlayer::stereo
    \brief In Stereo mode.
*/

/*!
    Returns true if in stereo.
*/

bool QRadioPlayer::isStereo() const
{
    return d_func()->control->isStereo();
}

/*!
    Returns true if \a b is an available band.
*/

bool QRadioPlayer::isSupportedBand(QRadioPlayer::Band b) const
{
    return d_func()->control->isSupportedBand(b);
}

/*!
    \property QRadioPlayer::signalStrength
    \brief The strength of the current radio signal as a percentage.
*/

/*!
    Returns the signal strength as a percentage.
*/

int QRadioPlayer::signalStrength() const
{
    return d_func()->control->signalStrength();
}

/*!
    \property QRadioPlayer::duration
    \brief The duration at current frequency in milliseconds.
*/

/*!
    Returns duration at current frequency in milliseconds.
*/

qint64 QRadioPlayer::duration() const
{
    return d_func()->control->duration();
}

/*!
    \property QRadioPlayer::volume
    \brief The current volume as a percentage.
*/

/*!
    Returns the volume as a percentage.
*/

int QRadioPlayer::volume() const
{
    return d_func()->control->volume();
}

/*!
    \property QRadioPlayer::muted
    \brief Returns true if muted.
*/

/*!
    Returns true if muted.
*/

bool QRadioPlayer::isMuted() const
{
    return d_func()->control->isMuted();
}

/*!
    Sets the band being used to \a band.
*/

void QRadioPlayer::setBand(QRadioPlayer::Band band)
{
    d_func()->control->setBand(band);
}

/*!
    Sets the frequency being used to \a frequency.
*/

void QRadioPlayer::setFrequency(int frequency)
{
    d_func()->control->setFrequency(frequency);
}

/*!
    If \a stereo is true, Sets to stereo mode, otherwise, mono mode.
*/

void QRadioPlayer::setStereo(bool stereo)
{
    d_func()->control->setStereo(stereo);
}

/*!
    Sets the volume to \a volume.
    volume is a percentage.
*/

void QRadioPlayer::setVolume(int volume)
{
    d_func()->control->setVolume(volume);
}

/*!
    If muted is true sets to mute, otherwise unmute.
*/

void QRadioPlayer::setMuted(bool muted)
{
    d_func()->control->setMuted(muted);
}

/*!
    Returns true if an available device.
*/

bool QRadioPlayer::isValid() const
{
    return QMediaObject::isValid() && d_func()->control != 0;
}

/*!
    \property QRadioPlayer::searching
    \brief Returns true if currently scanning.
*/

/*!
    Returns true if currently scanning.
*/

bool QRadioPlayer::isSearching() const
{
    return d_func()->control->isSearching();
}

/*!
    Start scanning through frequencies, ascending.
*/

void QRadioPlayer::searchForward()
{
    d_func()->control->searchForward();
}

/*!
    Start scanning through frequencies, descending.
*/

void QRadioPlayer::searchBackward()
{
    d_func()->control->searchBackward();
}

/*!
    Stop any scanning being done.
*/

void QRadioPlayer::cancelSearch()
{
    d_func()->control->cancelSearch();
}

/*!
    \fn void QRadioPlayer::bandChanged(QRadioPlayer::Band band)

    Signal the change in frequency range to \a band.
*/

/*!
    \fn void QRadioPlayer::frequencyChanged(int frequency)

    Signal the change in current \a frequency.
*/

/*!
    \fn void QRadioPlayer::mutingChanged(bool muted)

    Signal the change in mute condition to \a muted.
*/

/*!
    \fn void QRadioPlayer::volumeChanged(int volume)

    Signal the change in volume percentage to \a volume.
*/

/*!
    \fn void QRadioPlayer::searchingStatusChanged(bool searching)

    Signal the change in scanning mode to \a searching.
*/

/*!
    \fn void QRadioPlayer::stereoStatusChanged(bool stereo)

    Signal the change in stereo mode to \a stereo.
*/

/*!
    \fn void QRadioPlayer::durationChanged(qint64 duration)

    Signal the change in the \a duration of the current frequency playback in milliseconds.
*/

/*!
    \fn void QRadioPlayer::signalStrengthChanged(int signalStrength)

    Signal emitted when signal strength changes to new value \a signalStrength.
*/

/*!
    \enum QRadioPlayer::Band

    \value AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz
    \value FM 87.5 to 108.0 MHz, except Japan 76-90 MHz
    \value SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing
    \value LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia)
*/

<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_getcwd.h"
#include "MyString.h"

bool condor_getcwd(MyString &path) {
	size_t buflen = 0;
	char *buf = NULL;

		// Some platforms (supposedly) do not support getcwd(NULL),
		// so we do it the hard way...

	while(1) {
		buflen += 256;
		buf = (char *)malloc(buflen);
		if( !buf ) {
			return false;
		}

		if( getcwd(buf,buflen) != NULL ) {
			path = buf;
			free( buf );
			buf = NULL;
			break;
		}
		free( buf );
		buf = NULL;

		if( errno == ERANGE ) {
			continue; // try with a bigger buffer
		}
		return false;
	}

	return true;
}
<commit_msg>Fixed an obscure bug with getcwd() in condor_getcwd() that our unit tests found. Under Solaris, if getcwd() is called in a directory which is larger than PATH_MAX then getcwd() returns NULL and ERANGE regardless if the buffer and buflen passed into it are plenty big enough to hold the path or not--forever. Since condor_getcwd() tries to find a large enough path, it'll eventually consume all of the memory of the process and kill the process or cause other havoc on the machine.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_getcwd.h"
#include "MyString.h"
#include "condor_debug.h"

bool condor_getcwd(MyString &path) {
	size_t buflen = 0;
	char *buf = NULL;

		// Some platforms (supposedly) do not support getcwd(NULL),
		// so we do it the hard way...

	while(1) {
		buflen += 256;
		buf = (char *)malloc(buflen);
		if( !buf ) {
			return false;
		}

		if( getcwd(buf,buflen) != NULL ) {
			path = buf;
			free( buf );
			buf = NULL;
			break;
		}
		free( buf );
		buf = NULL;

		if( errno == ERANGE ) {
			// There is a bug in solaris' getcwd(). It returns NULL and
			// ERANGE if getcwd() is called in a directory whose real path
			// is larger than PATH_MAX even though the buf and buflen are
			// clearly big enough to hold it. Since getcwd() does this
			// always in this context, we could consume memory here until we
			// run out unless we keep tabs on how much we actually allocated.
			//
			// I'm going to fix it so that if we manage to go beyond 20 Megs of
			// memory trying to find room for our path, I'm declaring that to
			// be "too big", and bailing on the algorithm. Since other OSes
			// apparently have a similar style of error, I'm not going to make
			// this solaris specific. Frankly, if we need a 20M path, something
			// is wrong--or it is year 2317, file systems are huge, and someone
			// then can up it to 40M.
			//
			// This isn't going to be configurable, because that would be yet
			// another impossibly arcane knob noone would ever touch.
			//
			// -psilord 10/14/2010

			if (buflen > ((1024 * 1024) * 20)) {
				dprintf(D_ALWAYS,
					"condor_getcwd(): Unable to determine cwd. Avoiding "
					"a probable OS bug. Assuming getcwd() failed.\n");
				return false;
			}

			// try with a bigger buffer
			continue;
		}
		return false;
	}

	return true;
}
<|endoftext|>


<commit_before>#pragma once

#include "fwd.hpp"
#include "traceback.hpp"
#include "Converter.hpp"

#include <configure/error.hpp>

namespace configure { namespace lua {

	inline std::string empty_function_name() { return ""; }

	template<typename Ret, typename Fn, typename FnName = std::string(*)()>
	Ret store_exception(lua_State* state, Fn&& fn, FnName function_name = &empty_function_name)
	{
		try {
			try { return fn(); }
			catch (error::LuaError& e) {
				if (boost::get_error_info<error::lua_function>(e) == nullptr)
				{
					std::string name = function_name();
					if (!name.empty())
						e << error::lua_function(std::move(name));
				}
				if (boost::get_error_info<error::lua_traceback>(e) == nullptr)
					e << error::lua_traceback(traceback(state));
				throw;
			}
			catch (std::exception const&) {
				std::string name = function_name();
				if (!name.empty())
					CONFIGURE_THROW(
						error::LuaError("While Calling C++")
							<< error::lua_function(std::move(name))
							<< error::lua_traceback(traceback(state))
							<< error::nested(std::current_exception())
					);
				else
					CONFIGURE_THROW(
						error::LuaError("While Calling C++")
							<< error::lua_traceback(traceback(state))
							<< error::nested(std::current_exception())
					);
			}
			catch (...)
			{
				// This is a raw lua error (aka a pointer is thrown)
				// We let the exception bubble up, so that the enclosing error
				// handler will be triggered. However, we lost the function
				// name information.
				// This is fixable by extracting the real error message here.
				// (The error message is not yet on the stack).
				throw;
			}
		}
		catch (std::exception const&) {
			Converter<std::exception_ptr>::push(state, std::current_exception());
			lua_error(state);
		}
		std::abort();
	}

}}
<commit_msg>Better error message.<commit_after>#pragma once

#include "fwd.hpp"
#include "traceback.hpp"
#include "Converter.hpp"

#include <configure/error.hpp>

namespace configure { namespace lua {

	inline std::string empty_function_name() { return ""; }

	template<typename Ret, typename Fn, typename FnName = std::string(*)()>
	Ret store_exception(lua_State* state, Fn&& fn, FnName function_name = &empty_function_name)
	{
		try {
			try { return fn(); }
			catch (error::LuaError& e) {
				if (boost::get_error_info<error::lua_function>(e) == nullptr)
				{
					std::string name = function_name();
					if (!name.empty())
						e << error::lua_function(std::move(name));
				}
				if (boost::get_error_info<error::lua_traceback>(e) == nullptr)
					e << error::lua_traceback(traceback(state));
				throw;
			}
			catch (std::exception const&) {
				std::string name = function_name();
				if (!name.empty())
					CONFIGURE_THROW(
						error::LuaError("While Calling builtin")
							<< error::lua_function(std::move(name))
							<< error::lua_traceback(traceback(state))
							<< error::nested(std::current_exception())
					);
				else
					CONFIGURE_THROW(
						error::LuaError("While Calling builtin")
							<< error::lua_traceback(traceback(state))
							<< error::nested(std::current_exception())
					);
			}
			catch (...)
			{
				// This is a raw lua error (aka a pointer is thrown)
				// We let the exception bubble up, so that the enclosing error
				// handler will be triggered. However, we lost the function
				// name information.
				// This is fixable by extracting the real error message here.
				// (The error message is not yet on the stack).
				throw;
			}
		}
		catch (std::exception const&) {
			Converter<std::exception_ptr>::push(state, std::current_exception());
			lua_error(state);
		}
		std::abort();
	}

}}
<|endoftext|>


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

#include "c_sharp_wrapper.h"
#include <repo/core/model/bson/repo_node_material.h>
#include <repo/core/model/bson/repo_node_texture.h>
#include <repo/lib/repo_exception.h>
#include <boost/filesystem.hpp>
#include <fstream>

using namespace repo::lib;

CSharpWrapper* CSharpWrapper::wrapper = nullptr;

CSharpWrapper::CSharpWrapper()
	: controller(new repo::RepoController()),
	token(nullptr),
	scene(nullptr),
	vrEnabled(false)
{
}

CSharpWrapper::~CSharpWrapper()
{
	repoInfo << "@wrapper deconstructor";
	if (controller)
	{
		repoInfo << "Controller around, destroying token";
		if (token)
			controller->destroyToken(token);
		repoInfo << "Destroying scene...";
		if (scene)
			delete scene;
		repoInfo << "Destroying controller..";
		delete controller;

		repoInfo << "done";
	}

}

bool CSharpWrapper::connect(
	const std::string &config
)
{
	std::string msg;
	try {
		token = controller->init(msg, repo::lib::RepoConfig::fromFile(config));
		return token;
	} catch(const repo::lib::RepoException &exception) {
		return false;
	}
}

void CSharpWrapper::freeSuperMesh(
		const int &index)
{

	if (superMeshes.size() > index && superMeshes[index] != nullptr)
	{
		superMeshes[index] = nullptr;
	}
}

void CSharpWrapper::getIdMapBuffer(
	const int &index,
	const int &smIndex,
	float* &idMap) const
{
	if (idMapBuf.size() > index && idMapBuf[index].size() > smIndex)
	{
		memcpy(idMap, idMapBuf[index][smIndex].data(), sizeof(*idMap) * idMapBuf[index][smIndex].size());
	}
}

CSharpWrapper* CSharpWrapper::getInstance()
{
	if (!wrapper) {
		wrapper = new CSharpWrapper();
	}
	return wrapper;
}

void CSharpWrapper::destroyInstance() {
	if(wrapper) {
		delete wrapper;
	}
}

void CSharpWrapper::getMaterialInfo(
	const std::string &materialID,
	float* &diffuse,
	float* &specular,
	float* &shininess,
	float* &shininessStrength) const
{
	auto it = matNodes.find(materialID);
	if (it != matNodes.end())
	{
		*shininess = 0;
		*shininessStrength = 1;
		if (it->second.shininess == it->second.shininess)
			*shininess = it->second.shininess;
		if (it->second.shininessStrength == it->second.shininessStrength)
			*shininessStrength = it->second.shininessStrength;

		for (size_t i = 0; i < 3; i++)
		{
			diffuse[i] = 0.5;
			specular[i] = 0;
		}

		for (size_t i = 0; i < it->second.diffuse.size(); i++)
		{
			diffuse[i] = it->second.diffuse[i];
		}

		for (size_t i = 0; i < it->second.specular.size(); i++)
		{
			specular[i] = it->second.specular[i];
		}

		diffuse[3] = it->second.opacity;
	}
}

std::string CSharpWrapper::getOrgMeshInfoFromSubMesh(
	const int &index,
	const int &smIndex,
	const int &orgMeshIdx,
	int* &smFFrom,
	int* &smFTo) const
{
	std::string matID;
	if (meshMappings.size() > index &&
		meshMappings[index].size() > smIndex &&
		meshMappings[index][smIndex].size() > orgMeshIdx)
	{
		*smFFrom = meshMappings[index][smIndex][orgMeshIdx].triFrom;
		*smFTo = meshMappings[index][smIndex][orgMeshIdx].triTo;
		matID = meshMappings[index][smIndex][orgMeshIdx].material_id.toString();
	}

	return matID;
}

int CSharpWrapper::getNumSuperMeshes() const
{
	return superMeshes.size();
}

std::string CSharpWrapper::getRevisionList(
	const std::string &database,
	const std::string &project)
{
	auto revs = controller->getAllFromCollectionContinuous(token, database, project + ".history");
	repoTrace << "Trying to find revisions for " << database << "." << project;
	std::stringstream ss;
	bool first = true;
	for(const auto rev : revs)
	{
		auto id = repo::core::model::RepoNode(rev).getUniqueID().toString();
		if(first)
		{
			ss << id ;
			first = false;
		}
		else
		{
			ss << "," << id;
		}
	}

	return ss.str();
}

void CSharpWrapper::getSuperMeshBuffers(
	const int &index,
	float* &vertices,
	float* &normals,
	uint16_t* &faces,
	float* &uvs,
	int* &numOrgMeshes) const
{
	if (superMeshes.size() > index)
	{
		auto vBuf = superMeshes[index]->getVertices();
		size_t vByteSize = sizeof(*vBuf.data()) * vBuf.size();
		memcpy(vertices, vBuf.data(), vByteSize);
		auto normalsBuf = superMeshes[index]->getNormals();
		if(normalsBuf.size())
			memcpy(normals, normalsBuf.data(), vByteSize);
		memcpy(faces, serialisedFaceBuf[index].data(), sizeof(*serialisedFaceBuf[index].data()) * serialisedFaceBuf[index].size());

		auto uvs_in = superMeshes[index]->getUVChannelsSeparated();
		if (uvs_in.size())
		{
			memcpy(uvs, uvs_in[0].data(), sizeof(*uvs_in[0].data()) * uvs_in[0].size());
		}

		for (int i = 0; i < meshMappings[index].size(); ++i)
		{
			numOrgMeshes[i] = meshMappings[index][i].size();
		}

	}
}

void CSharpWrapper::getSubMeshInfo(const int &index,
	const int &subIdx,
	int32_t* &vFrom,
	int32_t* &vTo,
	int32_t* &fFrom,
	int32_t* &fTo) const
{
	if (superMeshes.size() > index)
	{
		auto smMapping = superMeshes[index]->getMeshMapping();
		if (smMapping.size() > subIdx)
		{
			auto mapping = smMapping[subIdx];
			*vFrom = mapping.vertFrom;
			*vTo = mapping.vertTo;
			*fFrom = mapping.triFrom;
			*fTo = mapping.triTo;
		}
	}
}

std::string CSharpWrapper::getSuperMeshInfo(
	const int &index,
	long* &subMeshes,
	long* &numVertices,
	long* &numFaces,
	bool* &hasNormals,
	bool* &hasUV,
	int* &primitiveType,
	int* &numMappings) const
{
	std::string res;
	if (superMeshes.size() > index)
	{
		*subMeshes = superMeshes[index]->getMeshMapping().size();
		*numVertices = superMeshes[index]->getVertices().size();
		*numFaces = superMeshes[index]->getFaces().size();
		*hasUV = superMeshes[index]->getUVChannels().size();
		*hasNormals = superMeshes[index]->getNormals().size();
		*primitiveType = static_cast<int>(superMeshes[index]->getPrimitive());
		*numMappings = numIdMappings[index];
		res = superMeshes[index]->getUniqueID().toString();
	}

	return res;
}

void CSharpWrapper::getTexture(
	char* materialID,
	char* texBuf) const
{
	auto it = matToTexture.find(materialID);
	if (it != matToTexture.end())
	{
		memcpy(texBuf, it->second.data(), sizeof(*texBuf) * it->second.size());
	}
}

std::string CSharpWrapper::getVersion() const
{
	std::stringstream ss;
	ss << "3D Repo Bouncer Version: " + controller->getVersion();
	return ss.str();
}

int CSharpWrapper::hasTexture(
	const std::string &materialID) const
{
	int res = -1;
	auto it = matToTexture.find(materialID);
	if (it != matToTexture.end())
	{
		res = it->second.size();
	}
	return res;
}

bool CSharpWrapper::initialiseSceneForAssetBundle(
	const std::string &database,
	const std::string &project,
	const std::string &revisionID)
{
	//clean up last job's data if available
	superMeshes.clear();
	jsonFiles.clear();
	serialisedFaceBuf.clear();
	idMapBuf.clear();
	meshMappings.clear();
	matNodes.clear();
	matToTexture.clear();
	numIdMappings.clear();

	if(scene)
		delete scene;

	if(revisionID.empty())
		scene = controller->fetchScene(token, database, project, REPO_HISTORY_MASTER_BRANCH, true,
				true, false, false, { repo::core::model::RevisionNode::UploadStatus::MISSING_BUNDLES });
	else
		scene = controller->fetchScene(token, database, project, revisionID, false,
				true, false, false, { repo::core::model::RevisionNode::UploadStatus::MISSING_BUNDLES });
	bool success  = false;
	if (scene)
	{
		projectName = project;
		databaseName = database;
		vrEnabled = controller->isVREnabled(token, scene);
		superMeshes = controller->initialiseAssetBuffer(token, scene, jsonFiles, unityAssets, serialisedFaceBuf, idMapBuf, meshMappings);
		success = superMeshes.size();

		// Get the total number of mappings contained in this supermesh. This is needed ahead of time to build things like textures.
		// We could consider passing this from the AssetModelExport in the future.

		for (auto splitMeshIdMap : idMapBuf) {
			numIdMappings.push_back(splitMeshIdMap.back().back() + 1);
		}

		//We dont' need the scene anymore
		for (auto mat : scene->getAllMaterials(repo::core::model::RepoScene::GraphType::OPTIMIZED))
		{
			auto matNode = dynamic_cast<repo::core::model::MaterialNode*>(mat);
			matNodes[mat->getUniqueID().toString()] = matNode->getMaterialStruct();
			auto textureChildren = scene->getChildrenNodesFiltered(
				repo::core::model::RepoScene::GraphType::OPTIMIZED,
				mat->getSharedID(),
				repo::core::model::NodeType::TEXTURE
				);
			if (textureChildren.size())
			{
				//There can only be 1 texture per material
				auto textNode = dynamic_cast<repo::core::model::TextureNode*>(textureChildren[0]);
				matToTexture[mat->getUniqueID().toString()] = textNode->getRawData();
			}
		}
		scene->clearStash();
	}

	return success;
}

bool CSharpWrapper::isVREnabled()
{
	return vrEnabled;
}

bool CSharpWrapper::isFederation(
				const std::string &database,
				const std::string &project) const
{
	auto tempScene = controller->fetchScene(token, database, project, REPO_HISTORY_MASTER_BRANCH, true, true);
	return tempScene && tempScene->getAllReferences(repo::core::model::RepoScene::GraphType::DEFAULT).size() > 0;
}

bool CSharpWrapper::saveAssetBundles(
	char** assetFiles,
	int      length
	)
{
	repo_web_buffers_t webBuffers;
	webBuffers.jsonFiles = jsonFiles;
	webBuffers.unityAssets = unityAssets;
	for (int i = 0; i < length; ++i)
	{
		std::ifstream inputStream;

		inputStream.open(assetFiles[i], std::ios::in | std::ios::binary);

		if (inputStream.is_open())
		{
			std::ostringstream ss;
			ss << inputStream.rdbuf();
			auto s = ss.str();
			boost::filesystem::path path(assetFiles[i]);
			std::string fileName = path.filename().string();
			fileName = "/" + databaseName + "/" + projectName + "/" + fileName;
			webBuffers.geoFiles[fileName] = std::vector<uint8_t>(s.begin(), s.end());
		}
		else
		{
			repoError << "Failed to find asset bundle";
			return false;
		}
	}

	return controller->commitAssetBundleBuffers(token, scene, webBuffers);
}
<commit_msg>ISSUE #531 remove debugging log<commit_after>/**
*  Copyright (C) 2017 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "c_sharp_wrapper.h"
#include <repo/core/model/bson/repo_node_material.h>
#include <repo/core/model/bson/repo_node_texture.h>
#include <repo/lib/repo_exception.h>
#include <boost/filesystem.hpp>
#include <fstream>

using namespace repo::lib;

CSharpWrapper* CSharpWrapper::wrapper = nullptr;

CSharpWrapper::CSharpWrapper()
	: controller(new repo::RepoController()),
	token(nullptr),
	scene(nullptr),
	vrEnabled(false)
{
}

CSharpWrapper::~CSharpWrapper()
{
	if (controller)
	{
		if (token)
			controller->destroyToken(token);
		if (scene)
			delete scene;
		delete controller;

	}

}

bool CSharpWrapper::connect(
	const std::string &config
)
{
	std::string msg;
	try {
		token = controller->init(msg, repo::lib::RepoConfig::fromFile(config));
		return token;
	} catch(const repo::lib::RepoException &exception) {
		return false;
	}
}

void CSharpWrapper::freeSuperMesh(
		const int &index)
{

	if (superMeshes.size() > index && superMeshes[index] != nullptr)
	{
		superMeshes[index] = nullptr;
	}
}

void CSharpWrapper::getIdMapBuffer(
	const int &index,
	const int &smIndex,
	float* &idMap) const
{
	if (idMapBuf.size() > index && idMapBuf[index].size() > smIndex)
	{
		memcpy(idMap, idMapBuf[index][smIndex].data(), sizeof(*idMap) * idMapBuf[index][smIndex].size());
	}
}

CSharpWrapper* CSharpWrapper::getInstance()
{
	if (!wrapper) {
		wrapper = new CSharpWrapper();
	}
	return wrapper;
}

void CSharpWrapper::destroyInstance() {
	if(wrapper) {
		delete wrapper;
	}
}

void CSharpWrapper::getMaterialInfo(
	const std::string &materialID,
	float* &diffuse,
	float* &specular,
	float* &shininess,
	float* &shininessStrength) const
{
	auto it = matNodes.find(materialID);
	if (it != matNodes.end())
	{
		*shininess = 0;
		*shininessStrength = 1;
		if (it->second.shininess == it->second.shininess)
			*shininess = it->second.shininess;
		if (it->second.shininessStrength == it->second.shininessStrength)
			*shininessStrength = it->second.shininessStrength;

		for (size_t i = 0; i < 3; i++)
		{
			diffuse[i] = 0.5;
			specular[i] = 0;
		}

		for (size_t i = 0; i < it->second.diffuse.size(); i++)
		{
			diffuse[i] = it->second.diffuse[i];
		}

		for (size_t i = 0; i < it->second.specular.size(); i++)
		{
			specular[i] = it->second.specular[i];
		}

		diffuse[3] = it->second.opacity;
	}
}

std::string CSharpWrapper::getOrgMeshInfoFromSubMesh(
	const int &index,
	const int &smIndex,
	const int &orgMeshIdx,
	int* &smFFrom,
	int* &smFTo) const
{
	std::string matID;
	if (meshMappings.size() > index &&
		meshMappings[index].size() > smIndex &&
		meshMappings[index][smIndex].size() > orgMeshIdx)
	{
		*smFFrom = meshMappings[index][smIndex][orgMeshIdx].triFrom;
		*smFTo = meshMappings[index][smIndex][orgMeshIdx].triTo;
		matID = meshMappings[index][smIndex][orgMeshIdx].material_id.toString();
	}

	return matID;
}

int CSharpWrapper::getNumSuperMeshes() const
{
	return superMeshes.size();
}

std::string CSharpWrapper::getRevisionList(
	const std::string &database,
	const std::string &project)
{
	auto revs = controller->getAllFromCollectionContinuous(token, database, project + ".history");
	repoTrace << "Trying to find revisions for " << database << "." << project;
	std::stringstream ss;
	bool first = true;
	for(const auto rev : revs)
	{
		auto id = repo::core::model::RepoNode(rev).getUniqueID().toString();
		if(first)
		{
			ss << id ;
			first = false;
		}
		else
		{
			ss << "," << id;
		}
	}

	return ss.str();
}

void CSharpWrapper::getSuperMeshBuffers(
	const int &index,
	float* &vertices,
	float* &normals,
	uint16_t* &faces,
	float* &uvs,
	int* &numOrgMeshes) const
{
	if (superMeshes.size() > index)
	{
		auto vBuf = superMeshes[index]->getVertices();
		size_t vByteSize = sizeof(*vBuf.data()) * vBuf.size();
		memcpy(vertices, vBuf.data(), vByteSize);
		auto normalsBuf = superMeshes[index]->getNormals();
		if(normalsBuf.size())
			memcpy(normals, normalsBuf.data(), vByteSize);
		memcpy(faces, serialisedFaceBuf[index].data(), sizeof(*serialisedFaceBuf[index].data()) * serialisedFaceBuf[index].size());

		auto uvs_in = superMeshes[index]->getUVChannelsSeparated();
		if (uvs_in.size())
		{
			memcpy(uvs, uvs_in[0].data(), sizeof(*uvs_in[0].data()) * uvs_in[0].size());
		}

		for (int i = 0; i < meshMappings[index].size(); ++i)
		{
			numOrgMeshes[i] = meshMappings[index][i].size();
		}

	}
}

void CSharpWrapper::getSubMeshInfo(const int &index,
	const int &subIdx,
	int32_t* &vFrom,
	int32_t* &vTo,
	int32_t* &fFrom,
	int32_t* &fTo) const
{
	if (superMeshes.size() > index)
	{
		auto smMapping = superMeshes[index]->getMeshMapping();
		if (smMapping.size() > subIdx)
		{
			auto mapping = smMapping[subIdx];
			*vFrom = mapping.vertFrom;
			*vTo = mapping.vertTo;
			*fFrom = mapping.triFrom;
			*fTo = mapping.triTo;
		}
	}
}

std::string CSharpWrapper::getSuperMeshInfo(
	const int &index,
	long* &subMeshes,
	long* &numVertices,
	long* &numFaces,
	bool* &hasNormals,
	bool* &hasUV,
	int* &primitiveType,
	int* &numMappings) const
{
	std::string res;
	if (superMeshes.size() > index)
	{
		*subMeshes = superMeshes[index]->getMeshMapping().size();
		*numVertices = superMeshes[index]->getVertices().size();
		*numFaces = superMeshes[index]->getFaces().size();
		*hasUV = superMeshes[index]->getUVChannels().size();
		*hasNormals = superMeshes[index]->getNormals().size();
		*primitiveType = static_cast<int>(superMeshes[index]->getPrimitive());
		*numMappings = numIdMappings[index];
		res = superMeshes[index]->getUniqueID().toString();
	}

	return res;
}

void CSharpWrapper::getTexture(
	char* materialID,
	char* texBuf) const
{
	auto it = matToTexture.find(materialID);
	if (it != matToTexture.end())
	{
		memcpy(texBuf, it->second.data(), sizeof(*texBuf) * it->second.size());
	}
}

std::string CSharpWrapper::getVersion() const
{
	std::stringstream ss;
	ss << "3D Repo Bouncer Version: " + controller->getVersion();
	return ss.str();
}

int CSharpWrapper::hasTexture(
	const std::string &materialID) const
{
	int res = -1;
	auto it = matToTexture.find(materialID);
	if (it != matToTexture.end())
	{
		res = it->second.size();
	}
	return res;
}

bool CSharpWrapper::initialiseSceneForAssetBundle(
	const std::string &database,
	const std::string &project,
	const std::string &revisionID)
{
	//clean up last job's data if available
	superMeshes.clear();
	jsonFiles.clear();
	serialisedFaceBuf.clear();
	idMapBuf.clear();
	meshMappings.clear();
	matNodes.clear();
	matToTexture.clear();
	numIdMappings.clear();

	if(scene)
		delete scene;

	if(revisionID.empty())
		scene = controller->fetchScene(token, database, project, REPO_HISTORY_MASTER_BRANCH, true,
				true, false, false, { repo::core::model::RevisionNode::UploadStatus::MISSING_BUNDLES });
	else
		scene = controller->fetchScene(token, database, project, revisionID, false,
				true, false, false, { repo::core::model::RevisionNode::UploadStatus::MISSING_BUNDLES });
	bool success  = false;
	if (scene)
	{
		projectName = project;
		databaseName = database;
		vrEnabled = controller->isVREnabled(token, scene);
		superMeshes = controller->initialiseAssetBuffer(token, scene, jsonFiles, unityAssets, serialisedFaceBuf, idMapBuf, meshMappings);
		success = superMeshes.size();

		// Get the total number of mappings contained in this supermesh. This is needed ahead of time to build things like textures.
		// We could consider passing this from the AssetModelExport in the future.

		for (auto splitMeshIdMap : idMapBuf) {
			numIdMappings.push_back(splitMeshIdMap.back().back() + 1);
		}

		//We dont' need the scene anymore
		for (auto mat : scene->getAllMaterials(repo::core::model::RepoScene::GraphType::OPTIMIZED))
		{
			auto matNode = dynamic_cast<repo::core::model::MaterialNode*>(mat);
			matNodes[mat->getUniqueID().toString()] = matNode->getMaterialStruct();
			auto textureChildren = scene->getChildrenNodesFiltered(
				repo::core::model::RepoScene::GraphType::OPTIMIZED,
				mat->getSharedID(),
				repo::core::model::NodeType::TEXTURE
				);
			if (textureChildren.size())
			{
				//There can only be 1 texture per material
				auto textNode = dynamic_cast<repo::core::model::TextureNode*>(textureChildren[0]);
				matToTexture[mat->getUniqueID().toString()] = textNode->getRawData();
			}
		}
		scene->clearStash();
	}

	return success;
}

bool CSharpWrapper::isVREnabled()
{
	return vrEnabled;
}

bool CSharpWrapper::isFederation(
				const std::string &database,
				const std::string &project) const
{
	auto tempScene = controller->fetchScene(token, database, project, REPO_HISTORY_MASTER_BRANCH, true, true);
	return tempScene && tempScene->getAllReferences(repo::core::model::RepoScene::GraphType::DEFAULT).size() > 0;
}

bool CSharpWrapper::saveAssetBundles(
	char** assetFiles,
	int      length
	)
{
	repo_web_buffers_t webBuffers;
	webBuffers.jsonFiles = jsonFiles;
	webBuffers.unityAssets = unityAssets;
	for (int i = 0; i < length; ++i)
	{
		std::ifstream inputStream;

		inputStream.open(assetFiles[i], std::ios::in | std::ios::binary);

		if (inputStream.is_open())
		{
			std::ostringstream ss;
			ss << inputStream.rdbuf();
			auto s = ss.str();
			boost::filesystem::path path(assetFiles[i]);
			std::string fileName = path.filename().string();
			fileName = "/" + databaseName + "/" + projectName + "/" + fileName;
			webBuffers.geoFiles[fileName] = std::vector<uint8_t>(s.begin(), s.end());
		}
		else
		{
			repoError << "Failed to find asset bundle";
			return false;
		}
	}

	return controller->commitAssetBundleBuffers(token, scene, webBuffers);
}
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Mula project
 * Copyright (c) 2011 Laszlo Papp <lpapp@kde.org>
 *
 * 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 "offsetcachefile.h"

#include "file.h"
#include "wordentry.h"

#include <QtCore/QVector>
#include <QtCore/QFile>
#include <QtCore/QtGlobal>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QPair>
#include <QtGui/QDesktopServices>

#include <arpa/inet.h>

using namespace MulaPluginStarDict;

class OffsetCacheFile::Private
{
    public:
        Private()
            : wordCount(0)
            , entryIndex(-1)
            , cacheMagicString("StarDict's Cache, Version: 0.1")
            , mappedData(0)
        {
        }

        ~Private()
        {
        }

        void fill(QByteArray data, int wordEntryCount, long index);

        static const int pageEntryNumber = 32;

        QVector<quint32> pageOffsetList;
        QFile indexFile;
        ulong wordCount;

        // The length of "word_str" should be less than 256, and then offset, size
        static const int wordEntrySize = 256 + sizeof(quint32)*2;

        // index/date based key and value pair
        QPair<int, QByteArray> first;
        QPair<int, QByteArray> last;
        QPair<int, QByteArray> middle;
        QPair<int, QByteArray> realLast;

        QByteArray pageData;

        long entryIndex;
        QList<WordEntry> entries;

        QByteArray cacheMagicString;
        QFile mapFile;
        uchar *mappedData;
};

void
OffsetCacheFile::Private::fill(QByteArray data, int wordEntryCount, long index)
{
    entryIndex = index;
    ulong position = 0;
    for (int i = 0; i < wordEntryCount; ++i)
    {
        entries[i].setData(data.mid(position));
        position = qstrlen(data.mid(position)) + 1;
        entries[i].setDataOffset(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
        entries[i].setDataSize(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
    }
}

OffsetCacheFile::OffsetCacheFile()
    : d(new Private)
{
}

OffsetCacheFile::~OffsetCacheFile()
{
}

QByteArray
OffsetCacheFile::readFirstWordDataOnPage(long pageIndex)
{
    int pageSize = d->pageOffsetList.at(pageIndex + 1) - d->pageOffsetList.at(pageIndex);
    int wordEntrySize = d->wordEntrySize;

    d->indexFile.seek(d->pageOffsetList.at(pageIndex));
    return d->indexFile.read(qMin(wordEntrySize, pageSize)); //TODO: check returned values, deal with word entry that strlen>255.
}

QByteArray
OffsetCacheFile::firstWordDataOnPage(long pageIndex)
{
    if (pageIndex < d->middle.first)
    {
        if (pageIndex == d->first.first)
            return d->first.second;

        return readFirstWordDataOnPage(pageIndex);
    }
    else if (pageIndex > d->middle.first)
    {
        if (pageIndex == d->last.first)
            return d->last.second;

        return readFirstWordDataOnPage(pageIndex);
    }
    else
    {
        return d->middle.second;
    }
}

QStringList
OffsetCacheFile::cacheLocations(const QString& completeFilePath)
{
    QStringList result;
    result.append(completeFilePath + ".oft");

    QString cacheLocation = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
    QFileInfo cacheLocationFileInfo(cacheLocation);
    QDir cacheLocationDir;

    if (!cacheLocationFileInfo.exists() && cacheLocationDir.mkdir(cacheLocation) == false)
        return result;

    if (!cacheLocationFileInfo.isDir())
        return result;

    result.append(cacheLocation + QDir::separator() + "sdcv" + QDir::separator() + QFileInfo(completeFilePath).fileName() + ".oft");
    return result;
}

bool
OffsetCacheFile::loadCache(const QString& completeFilePath)
{
    foreach (const QString& cacheLocation, cacheLocations(completeFilePath))
    {
        QFileInfo fileInfoIndex(completeFilePath);
        QFileInfo fileInfoCache(cacheLocation);

        if (fileInfoCache.lastModified() < fileInfoIndex.lastModified())
            continue;

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return false;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (d->cacheMagicString != d->mappedData)
            continue;

        memcpy(d->pageOffsetList.data(), d->mappedData + d->cacheMagicString.size(), d->pageOffsetList.size()*sizeof(d->pageOffsetList.at(0)));
        return true;
    }

    return false;
}

bool
OffsetCacheFile::saveCache(const QString& completeFilePath)
{
    foreach (const QString& cacheLocation, cacheLocations(completeFilePath))
    {
        QFile file(cacheLocation);
        if( !file.open( QIODevice::WriteOnly ) )
        {
            qDebug() << "Failed to open file for writing:" << cacheLocation;
            return false;
        }

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return false;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (file.write(d->cacheMagicString) != d->cacheMagicString.size())
            continue;

        if (file.write(reinterpret_cast<const char*>(d->pageOffsetList.data()), sizeof(d->pageOffsetList.at(0))*d->pageOffsetList.size())
                != d->pageOffsetList.at(0)*d->pageOffsetList.size())
            continue;

        file.close();

        qDebug() << "Save to cache" << completeFilePath;

        return true;
    }

    return false;
}

bool
OffsetCacheFile::load(const QString& completeFilePath, int wordCount, qulonglong fileSize)
{
    Q_UNUSED(fileSize);

    d->wordCount = wordCount;

    // Adding 1 is needed because the index file size is also stored
    if (wordCount % d->pageEntryNumber == 0)
        d->pageOffsetList.resize(wordCount / d->pageEntryNumber + 1);
    else
        d->pageOffsetList.resize(wordCount / d->pageEntryNumber + 2);

    if (!loadCache(completeFilePath))
    { //map file will close after finish of block
        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(completeFilePath);
        if (!d->mapFile.open(QIODevice::ReadOnly))
        {
            qDebug() << "Failed to open file:" << completeFilePath;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(completeFilePath);
            return false;
        }

        QByteArray byteArray = QByteArray::fromRawData(reinterpret_cast<const char*>(d->mappedData), d->mapFile.size());

        int position = 0;
        int j = 0;
        for (int i = 0; i < wordCount; ++i)
        {
            if (i % d->pageEntryNumber == 0)
            {
                d->pageOffsetList[j] = position;
                ++j;
            }

            position += qstrlen(byteArray.mid(position)) + 1 + 2 * sizeof(quint32);
        }

        if (!saveCache(completeFilePath))
            qDebug() << "Cache update failed";
    }

    d->indexFile.setFileName(completeFilePath);
    if (!d->indexFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "Failed to open file:" << completeFilePath;
        d->pageOffsetList.resize(0);
        return false;
    }

    d->first = qMakePair(0, readFirstWordDataOnPage(0));
    d->last = qMakePair(d->pageOffsetList.size() - 2, readFirstWordDataOnPage(d->pageOffsetList.size() - 2));
    d->middle = qMakePair((d->pageOffsetList.size() - 2) / 2, readFirstWordDataOnPage((d->pageOffsetList.size() - 2) / 2));
    d->realLast = qMakePair(wordCount - 1, key(wordCount - 1));

    return true;
}

ulong
OffsetCacheFile::loadPage(long pageIndex)
{
    ulong wordEntryCount = d->pageEntryNumber;
    if (pageIndex == ulong(d->pageOffsetList.size() - 2) && (wordEntryCount = d->wordCount % d->pageEntryNumber) == 0)
    {
        wordEntryCount = d->pageEntryNumber;
    }

    if (pageIndex != d->entryIndex)
    {
        d->indexFile.seek(d->pageOffsetList.at(pageIndex));

        d->pageData = d->indexFile.read(d->pageOffsetList[pageIndex + 1] - d->pageOffsetList[pageIndex]);
        d->fill(d->pageData, wordEntryCount, pageIndex);
    }

    return wordEntryCount;
}

QByteArray
OffsetCacheFile::key(long index)
{
    loadPage(index / d->pageEntryNumber);
    ulong indexInPage = index % d->pageEntryNumber;
    setWordEntryOffset(d->entries.at(indexInPage).dataOffset());
    setWordEntrySize(d->entries.at(indexInPage).dataSize());

    return d->entries.at(indexInPage).data();
}

bool
OffsetCacheFile::lookup(const QByteArray& word, long &index)
{
    bool found = false;
    long indexFrom;
    long indexTo = d->pageOffsetList.size() - 2;
    int cmpint;
    long indexThisIndex;
    if (stardictStringCompare(word, d->first.second) < 0)
    {
        index = 0;
        return false;
    }
    else if (stardictStringCompare(word, d->realLast.second) > 0)
    {
        index = invalidIndex;
        return false;
    }
    else
    {
        indexFrom = 0;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, firstWordDataOnPage(indexThisIndex));
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }
        if (!found)
            index = indexTo;    //prev
        else
            index = indexThisIndex;
    }

    if (!found)
    {
        ulong netr = loadPage(index);
        indexFrom = 1; // Needn't search the first word anymore.
        indexTo = netr - 1;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, d->entries.at(indexThisIndex).data());
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }

        index *= d->pageEntryNumber;
        if (!found)
            index += indexFrom;    //next
        else
            index += indexThisIndex;
    }
    else
    {
        index *= d->pageEntryNumber;
    }

    return found;
}

quint32
OffsetCacheFile::wordEntryOffset() const
{
    return AbstractIndexFile::wordEntryOffset();
}

void
OffsetCacheFile::setWordEntryOffset(quint32 wordEntryOffset)
{
    AbstractIndexFile::setWordEntryOffset(wordEntryOffset);
}

quint32
OffsetCacheFile::wordEntrySize() const
{
    return AbstractIndexFile::wordEntrySize();
}

void
OffsetCacheFile::setWordEntrySize(quint32 wordEntrySize)
{
    AbstractIndexFile::setWordEntrySize(wordEntrySize);
}
<commit_msg>Use append instead of unneccesary resize calculation and local variable<commit_after>/******************************************************************************
 * This file is part of the Mula project
 * Copyright (c) 2011 Laszlo Papp <lpapp@kde.org>
 *
 * 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 "offsetcachefile.h"

#include "file.h"
#include "wordentry.h"

#include <QtCore/QVector>
#include <QtCore/QFile>
#include <QtCore/QtGlobal>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QPair>
#include <QtGui/QDesktopServices>

#include <arpa/inet.h>

using namespace MulaPluginStarDict;

class OffsetCacheFile::Private
{
    public:
        Private()
            : wordCount(0)
            , entryIndex(-1)
            , cacheMagicString("StarDict's Cache, Version: 0.1")
            , mappedData(0)
        {
        }

        ~Private()
        {
        }

        void fill(QByteArray data, int wordEntryCount, long index);

        static const int pageEntryNumber = 32;

        QVector<quint32> pageOffsetList;
        QFile indexFile;
        ulong wordCount;

        // The length of "word_str" should be less than 256, and then offset, size
        static const int wordEntrySize = 256 + sizeof(quint32)*2;

        // index/date based key and value pair
        QPair<int, QByteArray> first;
        QPair<int, QByteArray> last;
        QPair<int, QByteArray> middle;
        QPair<int, QByteArray> realLast;

        QByteArray pageData;

        long entryIndex;
        QList<WordEntry> entries;

        QByteArray cacheMagicString;
        QFile mapFile;
        uchar *mappedData;
};

void
OffsetCacheFile::Private::fill(QByteArray data, int wordEntryCount, long index)
{
    entryIndex = index;
    ulong position = 0;
    for (int i = 0; i < wordEntryCount; ++i)
    {
        entries[i].setData(data.mid(position));
        position = qstrlen(data.mid(position)) + 1;
        entries[i].setDataOffset(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
        entries[i].setDataSize(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
    }
}

OffsetCacheFile::OffsetCacheFile()
    : d(new Private)
{
}

OffsetCacheFile::~OffsetCacheFile()
{
}

QByteArray
OffsetCacheFile::readFirstWordDataOnPage(long pageIndex)
{
    int pageSize = d->pageOffsetList.at(pageIndex + 1) - d->pageOffsetList.at(pageIndex);
    int wordEntrySize = d->wordEntrySize;

    d->indexFile.seek(d->pageOffsetList.at(pageIndex));
    return d->indexFile.read(qMin(wordEntrySize, pageSize)); //TODO: check returned values, deal with word entry that strlen>255.
}

QByteArray
OffsetCacheFile::firstWordDataOnPage(long pageIndex)
{
    if (pageIndex < d->middle.first)
    {
        if (pageIndex == d->first.first)
            return d->first.second;

        return readFirstWordDataOnPage(pageIndex);
    }
    else if (pageIndex > d->middle.first)
    {
        if (pageIndex == d->last.first)
            return d->last.second;

        return readFirstWordDataOnPage(pageIndex);
    }
    else
    {
        return d->middle.second;
    }
}

QStringList
OffsetCacheFile::cacheLocations(const QString& completeFilePath)
{
    QStringList result;
    result.append(completeFilePath + ".oft");

    QString cacheLocation = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
    QFileInfo cacheLocationFileInfo(cacheLocation);
    QDir cacheLocationDir;

    if (!cacheLocationFileInfo.exists() && cacheLocationDir.mkdir(cacheLocation) == false)
        return result;

    if (!cacheLocationFileInfo.isDir())
        return result;

    result.append(cacheLocation + QDir::separator() + "sdcv" + QDir::separator() + QFileInfo(completeFilePath).fileName() + ".oft");
    return result;
}

bool
OffsetCacheFile::loadCache(const QString& completeFilePath)
{
    foreach (const QString& cacheLocation, cacheLocations(completeFilePath))
    {
        QFileInfo fileInfoIndex(completeFilePath);
        QFileInfo fileInfoCache(cacheLocation);

        if (fileInfoCache.lastModified() < fileInfoIndex.lastModified())
            continue;

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return false;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (d->cacheMagicString != d->mappedData)
            continue;

        memcpy(d->pageOffsetList.data(), d->mappedData + d->cacheMagicString.size(), d->pageOffsetList.size()*sizeof(d->pageOffsetList.at(0)));
        return true;
    }

    return false;
}

bool
OffsetCacheFile::saveCache(const QString& completeFilePath)
{
    foreach (const QString& cacheLocation, cacheLocations(completeFilePath))
    {
        QFile file(cacheLocation);
        if( !file.open( QIODevice::WriteOnly ) )
        {
            qDebug() << "Failed to open file for writing:" << cacheLocation;
            return false;
        }

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return false;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (file.write(d->cacheMagicString) != d->cacheMagicString.size())
            continue;

        if (file.write(reinterpret_cast<const char*>(d->pageOffsetList.data()), sizeof(d->pageOffsetList.at(0))*d->pageOffsetList.size())
                != d->pageOffsetList.at(0)*d->pageOffsetList.size())
            continue;

        file.close();

        qDebug() << "Save to cache" << completeFilePath;

        return true;
    }

    return false;
}

bool
OffsetCacheFile::load(const QString& completeFilePath, int wordCount, qulonglong fileSize)
{
    Q_UNUSED(fileSize);

    d->wordCount = wordCount;

    // Adding 1 is needed because the index file size is also stored
    // if (wordCount % d->pageEntryNumber == 0)
        // d->pageOffsetList.resize(wordCount / d->pageEntryNumber + 1);
    // else
        // d->pageOffsetList.resize(wordCount / d->pageEntryNumber + 2);

    if (!loadCache(completeFilePath))
    { //map file will close after finish of block
        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(completeFilePath);
        if (!d->mapFile.open(QIODevice::ReadOnly))
        {
            qDebug() << "Failed to open file:" << completeFilePath;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(completeFilePath);
            return false;
        }

        QByteArray byteArray = QByteArray::fromRawData(reinterpret_cast<const char*>(d->mappedData), d->mapFile.size());

        int position = 0;
        d->pageOffsetList.clear();
        for (int i = 0; i < wordCount; ++i)
        {
            if (i % d->pageEntryNumber == 0)
                d->pageOffsetList.append(position);

            position += qstrlen(byteArray.mid(position)) + 1 + 2 * sizeof(quint32);
        }

        if (!saveCache(completeFilePath))
            qDebug() << "Cache update failed";
    }

    d->indexFile.setFileName(completeFilePath);
    if (!d->indexFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "Failed to open file:" << completeFilePath;
        d->pageOffsetList.clear();
        return false;
    }

    d->first = qMakePair(0, readFirstWordDataOnPage(0));
    d->last = qMakePair(d->pageOffsetList.size() - 2, readFirstWordDataOnPage(d->pageOffsetList.size() - 2));
    d->middle = qMakePair((d->pageOffsetList.size() - 2) / 2, readFirstWordDataOnPage((d->pageOffsetList.size() - 2) / 2));
    d->realLast = qMakePair(wordCount - 1, key(wordCount - 1));

    return true;
}

ulong
OffsetCacheFile::loadPage(long pageIndex)
{
    ulong wordEntryCount = d->pageEntryNumber;
    if (pageIndex == ulong(d->pageOffsetList.size() - 2) && (wordEntryCount = d->wordCount % d->pageEntryNumber) == 0)
    {
        wordEntryCount = d->pageEntryNumber;
    }

    if (pageIndex != d->entryIndex)
    {
        d->indexFile.seek(d->pageOffsetList.at(pageIndex));

        d->pageData = d->indexFile.read(d->pageOffsetList[pageIndex + 1] - d->pageOffsetList[pageIndex]);
        d->fill(d->pageData, wordEntryCount, pageIndex);
    }

    return wordEntryCount;
}

QByteArray
OffsetCacheFile::key(long index)
{
    loadPage(index / d->pageEntryNumber);
    ulong indexInPage = index % d->pageEntryNumber;
    setWordEntryOffset(d->entries.at(indexInPage).dataOffset());
    setWordEntrySize(d->entries.at(indexInPage).dataSize());

    return d->entries.at(indexInPage).data();
}

bool
OffsetCacheFile::lookup(const QByteArray& word, long &index)
{
    bool found = false;
    long indexFrom;
    long indexTo = d->pageOffsetList.size() - 2;
    int cmpint;
    long indexThisIndex;
    if (stardictStringCompare(word, d->first.second) < 0)
    {
        index = 0;
        return false;
    }
    else if (stardictStringCompare(word, d->realLast.second) > 0)
    {
        index = invalidIndex;
        return false;
    }
    else
    {
        indexFrom = 0;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, firstWordDataOnPage(indexThisIndex));
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }
        if (!found)
            index = indexTo;    //prev
        else
            index = indexThisIndex;
    }

    if (!found)
    {
        ulong netr = loadPage(index);
        indexFrom = 1; // Needn't search the first word anymore.
        indexTo = netr - 1;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, d->entries.at(indexThisIndex).data());
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }

        index *= d->pageEntryNumber;
        if (!found)
            index += indexFrom;    //next
        else
            index += indexThisIndex;
    }
    else
    {
        index *= d->pageEntryNumber;
    }

    return found;
}

quint32
OffsetCacheFile::wordEntryOffset() const
{
    return AbstractIndexFile::wordEntryOffset();
}

void
OffsetCacheFile::setWordEntryOffset(quint32 wordEntryOffset)
{
    AbstractIndexFile::setWordEntryOffset(wordEntryOffset);
}

quint32
OffsetCacheFile::wordEntrySize() const
{
    return AbstractIndexFile::wordEntrySize();
}

void
OffsetCacheFile::setWordEntrySize(quint32 wordEntrySize)
{
    AbstractIndexFile::setWordEntrySize(wordEntrySize);
}
<|endoftext|>