| 98 | } |
| 99 | |
| 100 | std::string insert(const char* begin1, const char* end1, |
| 101 | label_pair* begin2, label_pair* end2) |
| 102 | { |
| 103 | // sort the input labels and remove duplicate keys |
| 104 | std::sort(begin2, end2, label_key_less); |
| 105 | end2 = std::unique(begin2, end2, label_key_equal); |
| 106 | |
| 107 | // find the first delimiter that marks the end of the counter name |
| 108 | auto pos = std::find(begin1, end1, DELIMITER); |
| 109 | |
| 110 | // calculate the total size and preallocate the buffer |
| 111 | auto size = std::distance(begin1, end1); |
| 112 | if (pos == end1) { // add a delimiter if the key doesn't have one |
| 113 | size += sizeof(DELIMITER); |
| 114 | } |
| 115 | size = std::accumulate(begin2, end2, size, |
| 116 | [] (std::size_t sum, const label_pair& l) { |
| 117 | return sum + label_size(l); |
| 118 | }); |
| 119 | std::string result; |
| 120 | result.resize(size); |
| 121 | |
| 122 | // copy the counter name without the delimiter |
| 123 | auto out = std::copy(begin1, pos, result.begin()); |
| 124 | if (pos != end1) { |
| 125 | ++pos; // advance past the delimiter |
| 126 | } |
| 127 | *(out++) = DELIMITER; |
| 128 | |
| 129 | // merge the two sorted input ranges, drop any duplicate keys, and write |
| 130 | // them to output. the begin2 range is first so that new input labels can |
| 131 | // replace existing duplicates |
| 132 | auto end = std::set_union(begin2, end2, |
| 133 | label_iterator{pos, end1}, |
| 134 | label_iterator{end1, end1}, |
| 135 | label_insert_iterator{out}, |
| 136 | label_key_less); |
| 137 | // fix up the size in case set_union() removed any duplicates |
| 138 | result.resize(std::distance(result.begin(), end.base())); |
| 139 | |
| 140 | return result; |
| 141 | } |
| 142 | |
| 143 | std::string_view name(const char* begin, const char* end) |
| 144 | { |