| 101 | }; |
| 102 | |
| 103 | struct Partitioner { |
| 104 | public: |
| 105 | explicit Partitioner(int64 work_size, int32 num_parts) { |
| 106 | if (work_size <= 0 || num_parts <= 0) { return; } |
| 107 | num_parts_ = num_parts; |
| 108 | parts_.reserve(num_parts); |
| 109 | int64 start = 0; |
| 110 | for (int32 i = 0; i < num_parts; ++i) { |
| 111 | int64 end = start + (work_size + i) / num_parts; |
| 112 | parts_.emplace_back(Range(start, end)); |
| 113 | start = end; |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | const Range* GetRange(const int32 id) const { |
| 118 | if (id < 0 || id >= num_parts_) { return nullptr; } |
| 119 | return &parts_[id]; |
| 120 | } |
| 121 | |
| 122 | bool LocatePos(const int64 pos, int32* task_id) const { |
| 123 | for (int32 i = 0; i < num_parts_; ++i) { |
| 124 | if (pos >= parts_[i].Start() && pos < parts_[i].End()) { |
| 125 | *task_id = i; |
| 126 | return true; |
| 127 | } |
| 128 | } |
| 129 | return false; |
| 130 | } |
| 131 | |
| 132 | private: |
| 133 | std::vector<Range> parts_; |
| 134 | int32 num_parts_ = 0; |
| 135 | }; |
| 136 | |
| 137 | namespace { |
| 138 | struct IdHash : public std::hash<int64> { |