aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Dictionaries/Embedded/RegionsHierarchy.h
blob: 508bca0d1e1837920e642d28493cdd4fedc40680 (plain) (blame)
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
#pragma once

#include <vector>
#include <boost/noncopyable.hpp>
#include <base/types.h>
#include "GeodataProviders/IHierarchiesProvider.h"
#include <Core/Defines.h>


class IRegionsHierarchyDataProvider;

/** A class that lets you know if a region belongs to one RegionID region with another RegionID.
  * Information about the hierarchy of regions is downloaded from a text file.
  * Can on request update the data.
  */
class RegionsHierarchy : private boost::noncopyable
{
private:
    /// Relationship parent; 0, if there are no parents, the usual lookup table.
    using RegionParents = std::vector<RegionID>;
    /// type of region
    using RegionTypes = std::vector<RegionType>;
    /// depth in the tree, starting from the country (country: 1, root: 0)
    using RegionDepths = std::vector<RegionDepth>;
    /// population of the region. If more than 2 ^ 32 - 1, then it is equated to this maximum.
    using RegionPopulations = std::vector<RegionPopulation>;

    /// region -> parent region
    RegionParents parents;
    /// region -> city, including it or 0, if there is none
    RegionParents city;
    /// region -> country including it or 0, if there is none
    RegionParents country;
    /// region -> area that includes it or 0, if not
    RegionParents area;
    /// region -> district, including it or 0, if there is none
    RegionParents district;
    /// region -> the continent (the first when climbing in the hierarchy of regions), including it or 0, if there is none
    RegionParents continent;
    /// region -> the continent (the latter when you climb the hierarchy of regions), including it or 0, if there is none
    RegionParents top_continent;

    /// region -> population or 0, if unknown.
    RegionPopulations populations;

    /// region - depth in the tree
    RegionDepths depths;

    IRegionsHierarchyDataSourcePtr data_source;

public:
    explicit RegionsHierarchy(IRegionsHierarchyDataSourcePtr data_source_);

    /// Reloads, if necessary, the hierarchy of regions. Not threadsafe.
    void reload();


    bool in(RegionID lhs, RegionID rhs) const
    {
        if (lhs >= parents.size())
            return false;

        for (size_t i = 0; lhs != 0 && lhs != rhs && i < DBMS_HIERARCHICAL_DICTIONARY_MAX_DEPTH; ++i)
            lhs = parents[lhs];

        return lhs != 0;
    }

    RegionID toCity(RegionID region) const
    {
        if (region >= city.size())
            return 0;
        return city[region];
    }

    RegionID toCountry(RegionID region) const
    {
        if (region >= country.size())
            return 0;
        return country[region];
    }

    RegionID toArea(RegionID region) const
    {
        if (region >= area.size())
            return 0;
        return area[region];
    }

    RegionID toDistrict(RegionID region) const
    {
        if (region >= district.size())
            return 0;
        return district[region];
    }

    RegionID toContinent(RegionID region) const
    {
        if (region >= continent.size())
            return 0;
        return continent[region];
    }

    RegionID toTopContinent(RegionID region) const
    {
        if (region >= top_continent.size())
            return 0;
        return top_continent[region];
    }

    RegionID toParent(RegionID region) const
    {
        if (region >= parents.size())
            return 0;
        return parents[region];
    }

    RegionDepth getDepth(RegionID region) const
    {
        if (region >= depths.size())
            return 0;
        return depths[region];
    }

    RegionPopulation getPopulation(RegionID region) const
    {
        if (region >= populations.size())
            return 0;
        return populations[region];
    }
};