Welcome to mirror list, hosted at ThFree Co, Russian Federation.

drules_city_rank_table.cpp « indexer - github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 59cab838b965b5a786cf25cc483a38a7fb22eac8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
#include "indexer/drules_city_rank_table.hpp"
#include "indexer/scales.hpp"

#include "std/algorithm.hpp"
#include "std/bind.hpp"
#include "std/exception.hpp"
#include "std/function.hpp"
#include "std/unordered_map.hpp"
#include "std/utility.hpp"
#include "std/vector.hpp"

#include "base/assert.hpp"

namespace drule
{

namespace
{

using TZoomRange = pair<uint32_t, uint32_t>;
using TPopulationRange = pair<uint32_t, uint32_t>;
using TRankForPopulationRange = pair<double, TPopulationRange>;
using TCityRankVector = vector<TRankForPopulationRange>;
using TCityRankTable = unordered_map<uint32_t, TCityRankVector>;

class ConstCityRankTable : public ICityRankTable
{
public:
  explicit ConstCityRankTable(double rank)
    : m_rank(rank)
  {
  }

  bool GetCityRank(uint32_t /*zoomLevel*/, uint32_t /*population*/, double & rank) const override
  {
    rank = m_rank;
    return true;
  }

private:
  double const m_rank;
};

class CityRankTable : public ICityRankTable
{
public:
  explicit CityRankTable(TCityRankTable && table)
    : m_table(move(table))
  {
  }

  bool GetCityRank(uint32_t zoomLevel, uint32_t population, double & rank) const override
  {
    auto const itr = m_table.find(zoomLevel);
    if (itr == m_table.cend())
      return false;

    for (auto const & rp : itr->second)
    {
      if (population >= rp.second.first && population <= rp.second.second)
      {
        rank = rp.first;
        return true;
      }
    }

    return false;
  }

private:
  TCityRankTable const m_table;
};

void RemoveSpaces(string & s)
{    
  s.erase(remove_if(s.begin(), s.end(), &isspace), s.end());
}

bool ParseZoom(string const & s, size_t start, size_t end,
               uint32_t & zFrom, uint32_t & zTo)
{
  ASSERT_LESS(start, end, ());
  ASSERT_LESS(end, s.length(), ());

  // Parse Zoom
  // z[zoomFrom]-[zoomTo]
  // z[zoom]

  // length of Zoom must be more than 1 because it starts with z
  if ((end - start) <= 1)
    return false;

  if (s[start] != 'z')
    return false;

  string zFromStr, zToStr;

  size_t const d = s.find('-', start + 1);
  if (d == string::npos || d >= end)
  {
    zFromStr.assign(s.begin() + start + 1, s.begin() + end);
    zToStr = zFromStr;
  }
  else
  {
    zFromStr.assign(s.begin() + start + 1, s.begin() + d);
    zToStr.assign(s.begin() + d + 1, s.begin() + end);
  }

  try
  {
    zFrom = zFromStr.empty() ? 0 : stoi(zFromStr);
    zTo = zToStr.empty() ? scales::UPPER_STYLE_SCALE : stoi(zToStr);
  }
  catch (exception &)
  {
    // stoi has not parsed a number
    return false;
  }

  if (zFrom > zTo)
    return false;

  return true;
}

bool ParsePopulationRank(string const & s, size_t start, size_t end,
                         uint32_t & popFrom, uint32_t & popTo, double & rank)
{
  ASSERT_LESS(start, end, ());
  ASSERT_LESS(end, s.length(), ());

  // Parse PopulationRank
  // [populationFrom]-[populationTo]:rank

  size_t const d1 = s.find('-', start);
  if (d1 == string::npos || d1 >= end)
    return false;

  size_t const d2 = s.find(':', d1 + 1);
  if (d2 == string::npos || d2 >= end)
    return false;

  string popFromStr(s.begin() + start, s.begin() + d1);
  string popToStr(s.begin() + d1 + 1, s.begin() + d2);
  string rankStr(s.begin() + d2 + 1, s.begin() + end);

  try
  {
    popFrom = popFromStr.empty() ? 0 : stoi(popFromStr);
    popTo = popToStr.empty() ? numeric_limits<uint32_t>::max() : stoi(popToStr);
    rank = stod(rankStr);
  }
  catch (exception &)
  {
    // stoi, stod has not parsed a number
    return false;
  }

  if (popFrom > popTo)
    return false;

  return true;
}

bool ParsePopulationRanks(string const & s, size_t start, size_t end,
                          function<void(uint32_t, uint32_t, double)> const & onPopRank)
{
  ASSERT_LESS(start, end, ());
  ASSERT_LESS(end, s.length(), ());

  // Parse 0...n of PopulationRank, delimited by ;

  while (start < end)
  {
    size_t const i = s.find(';', start);
    if (i == string::npos || i >= end)
      return false;

    if (i > start)
    {
      uint32_t popFrom, popTo;
      double rank;
      if (!ParsePopulationRank(s, start, i, popFrom, popTo, rank))
        return false;

      onPopRank(popFrom, popTo, rank);
    }

    start = i + 1;
  }

  return true;
}

bool ParseCityRankTable(string const & s,
                        function<void(uint32_t, uint32_t)> const & onZoom,
                        function<void(uint32_t, uint32_t, double)> const & onPopRank)
{
  // CityRankTable string format is
  // z[zoomFrom]-[zoomTo] { [populationFrom]-[populationTo]:rank;[populationFrom]-[populationTo]:rank; }

  size_t const end = s.length();
  size_t start = 0;

  while (start < end)
  {
    size_t const i = s.find('{', start);
    if (i == string::npos)
      return false;

    size_t const j = s.find('}', i + 1);
    if (j == string::npos)
      return false;

    uint32_t zFrom, zTo;
    if (!ParseZoom(s, start, i, zFrom, zTo))
      return false;

    if (j > (i + 1))
    {
      onZoom(zFrom, zTo);

      if (!ParsePopulationRanks(s, i + 1, j, onPopRank))
        return false;
    }

    start = j + 1;
  }

  return true;
}

class CityRankTableBuilder
{
public:
  unique_ptr<ICityRankTable> Parse(string & str)
  {
    RemoveSpaces(str);

    auto onZoom = bind(&CityRankTableBuilder::OnZoom, this, _1, _2);
    auto onPopRank = bind(&CityRankTableBuilder::OnPopulationRank, this, _1, _2, _3);
    if (!ParseCityRankTable(str, onZoom, onPopRank))
      return unique_ptr<ICityRankTable>();

    Flush();

    return make_unique<CityRankTable>(move(m_cityRanksTable));
  }

private:
  void OnPopulationRank(uint32_t popFrom, uint32_t popTo, double rank)
  {
    m_cityRanksForZoomRange.emplace_back(make_pair(rank, make_pair(popFrom, popTo)));
  }
  void OnZoom(uint32_t zoomFrom, uint32_t zoomTo)
  {
    Flush();

    m_zoomRange = make_pair(zoomFrom, zoomTo);
  }
  void Flush()
  {
    if (!m_cityRanksForZoomRange.empty())
    {
      for (uint32_t z = m_zoomRange.first; z <= m_zoomRange.second; ++z)
      {
        TCityRankVector & dst = m_cityRanksTable[z];
        dst.insert(dst.end(), m_cityRanksForZoomRange.begin(), m_cityRanksForZoomRange.end());
      }
      m_cityRanksForZoomRange.clear();
    }
  }

  TZoomRange m_zoomRange;
  TCityRankVector m_cityRanksForZoomRange;
  TCityRankTable m_cityRanksTable;
};

}  // namespace

unique_ptr<ICityRankTable> GetCityRankTableFromString(string & str)
{
  return CityRankTableBuilder().Parse(str);
}

unique_ptr<ICityRankTable> GetConstRankCityRankTable(double rank)
{
  return unique_ptr<ICityRankTable>(new ConstCityRankTable(rank));
}

}  // namespace drule