<commit_before>#include "tile_info.hpp"
#include "engine_context.hpp"
#include "stylist.hpp"
#include "rule_drawer.hpp"

#include "../map/feature_vec_model.hpp"

#include "../std/bind.hpp"

namespace
{
  struct IDsAccumulator
  {
    IDsAccumulator(vector<FeatureID> & ids, vector<df::FeatureInfo> const & src)
      : m_ids(ids)
      , m_src(src)
    {
    }

    void operator()(size_t index)
    {
      ASSERT_LESS(index, m_src.size(), ());
      m_ids.push_back(m_src[index].m_id);
    }

    vector<FeatureID> & m_ids;
    vector<df::FeatureInfo> const & m_src;
  };
}

namespace df
{
  TileInfo::TileInfo(TileKey const & key)
    : m_key(key)
    , m_isCanceled(false)
  {}

  m2::RectD TileInfo::GetGlobalRect() const
  {
    return m_key.GetGlobalRect();
  }

  void TileInfo::ReadFeatureIndex(model::FeaturesFetcher const & model)
  {
    if (DoNeedReadIndex())
    {
      threads::MutexGuard guard(m_mutex);
      CheckCanceled();
      model.ForEachFeatureID(GetGlobalRect(), *this, m_key.m_zoomLevel);
      sort(m_featureInfo.begin(), m_featureInfo.end());
    }
  }

  void TileInfo::ReadFeatures(model::FeaturesFetcher const & model,
                              MemoryFeatureIndex & memIndex,
                              EngineContext & context)
  {
    CheckCanceled();
    vector<size_t> indexes;
    RequestFeatures(memIndex, indexes);

    if (!indexes.empty())
    {
      context.BeginReadTile(m_key);
      vector<FeatureID> featuresToRead;
      for_each(indexes.begin(), indexes.end(), IDsAccumulator(featuresToRead, m_featureInfo));

      RuleDrawer drawer(bind(&TileInfo::InitStylist, this, _1 ,_2), m_key, context);
      model.ReadFeatures(drawer, featuresToRead);
      context.EndReadTile(m_key);
    }
  }

  void TileInfo::Cancel(MemoryFeatureIndex & memIndex)
  {
    m_isCanceled = true;<commit_msg>[drape] EndReadTile must be called anyway<commit_after>#include "tile_info.hpp"
#include "engine_context.hpp"
#include "stylist.hpp"
#include "rule_drawer.hpp"

#include "../base/scope_guard.hpp"
#include "../map/feature_vec_model.hpp"

#include "../std/bind.hpp"

namespace
{
  struct IDsAccumulator
  {
    IDsAccumulator(vector<FeatureID> & ids, vector<df::FeatureInfo> const & src)
      : m_ids(ids)
      , m_src(src)
    {
    }

    void operator()(size_t index)
    {
      ASSERT_LESS(index, m_src.size(), ());
      m_ids.push_back(m_src[index].m_id);
    }

    vector<FeatureID> & m_ids;
    vector<df::FeatureInfo> const & m_src;
  };
}

namespace df
{
  TileInfo::TileInfo(TileKey const & key)
    : m_key(key)
    , m_isCanceled(false)
  {}

  m2::RectD TileInfo::GetGlobalRect() const
  {
    return m_key.GetGlobalRect();
  }

  void TileInfo::ReadFeatureIndex(model::FeaturesFetcher const & model)
  {
    if (DoNeedReadIndex())
    {
      threads::MutexGuard guard(m_mutex);
      CheckCanceled();
      model.ForEachFeatureID(GetGlobalRect(), *this, m_key.m_zoomLevel);
      sort(m_featureInfo.begin(), m_featureInfo.end());
    }
  }

  void TileInfo::ReadFeatures(model::FeaturesFetcher const & model,
                              MemoryFeatureIndex & memIndex,
                              EngineContext & context)
  {
    CheckCanceled();
    vector<size_t> indexes;
    RequestFeatures(memIndex, indexes);

    if (!indexes.empty())
    {
      context.BeginReadTile(m_key);

      // Reading can be interrupted by exception throwing
      MY_SCOPE_GUARD(ReleaseReadTile, bind(&EngineContext::EndReadTile, &context, m_key));

      vector<FeatureID> featuresToRead;
      for_each(indexes.begin(), indexes.end(), IDsAccumulator(featuresToRead, m_featureInfo));

      RuleDrawer drawer(bind(&TileInfo::InitStylist, this, _1 ,_2), m_key, context);
      model.ReadFeatures(drawer, featuresToRead);
    }
  }

  void TileInfo::Cancel(MemoryFeatureIndex & memIndex)
  {
    m_isCanceled = true;
{'fraction_non_alphanumeric': 0.13102019678922838, 'fraction_numerical': 0.0015535991714137752, 'mean_word_length': 3.306577480490524, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3838786', 'n_tokens_mistral': 1333, 'n_tokens_neox': 1310, 'n_words': 208}