Repository: opencv/opencv
File: modules/dnn/src/layers/unique_layer.cpp (C++)

Code before:
            const uchar* base = X.ptr();
            int64 total = X.total();
            for (int64 t = 0; t < total; ++t)
            {
                int j = idx[ax];
                int64 lin = 0;
                for (int k = 0; k < r; ++k) if (k != ax) lin += (int64)idx[k] * mult[k];
                uchar* dst = keys[j].data() + (size_t)lin * elemSz;
                size_t off = 0;
                for (int k = 0; k < r; ++k) off += (size_t)idx[k] * stepB[k];
                const uchar* src = base + off;
                std::memcpy(dst, src, elemSz);
                for (int k = r - 1; k >= 0; --k) {
                    if (++idx[k] < X.size[k]) break;
                    idx[k] = 0;
                }
            }
        }

        std::unordered_map<std::string, int> where; where.reserve(A*2+1);
        std::vector<std::string> uniqKeyStr; uniqKeyStr.reserve(A);
        std::vector<int> firstJ; firstJ.reserve(A);
        std::vector<int64> counts; counts.reserve(A);
        std::vector<int> inv(A, -1);

        auto keyToStr = [](const std::vector<uchar>& v)->std::string {
            return std::string(reinterpret_cast<const char*>(v.data()), v.size());
        };

        for (int j = 0; j < A; ++j) {
            std::string s = keyToStr(keys[j]);
            auto it = where.find(s);
            if (it == where.end()) {
                int yi = (int)uniqKeyStr.size();
                where.emplace(s, yi);
                uniqKeyStr.push_back(std::move(s));
                firstJ.push_back(j);
                counts.push_back(1);
                inv[j] = yi;
            } else {
                counts[it->second] += 1;
                inv[j] = it->second;
            }
        }

        std::vector<int> order(uniqKeyStr.size());
        std::iota(order.begin(), order.end(), 0);
        if (sorted) {
            const size_t elemSzBytes = elemSz;
            const size_t elemsPerSlice = (size_t)sliceElems;
            auto numericLess = [&](int a, int b){

Review comment (suggestion):
OpenCV DNN does not support tensors of strings, only tensors of numbers. Don't convert numbers to strings, use template implementation to support different types.

Code after:
        std::vector<int64> counts; counts.reserve(A);
        std::vector<int> inv(A, -1);

        if (ax < 0)
        {
            using Pair = std::pair<int, WT>; // (original index, value)
            std::vector<Pair> keyed(A);
            for (int u = 0; u < A; ++u)
                keyed[u] = {u, static_cast<WT>(inPtr[(size_t)u])};

            auto lessPair = [](const WT& a, const WT& b){ return a < b; };
            auto equalPair = [](const WT& a, const WT& b){ return a == b; };
            sortAndGroupKeys(keyed, lessPair, equalPair, groupRepIndex, firstJ, counts, inv);
        }
        else
        {
            const size_t S = (size_t)sliceElems;
            std::vector<WT> flat((size_t)A * S);
            for (int u = 0; u < A; ++u)
            {
                size_t wrote = 0;
                for (size_t ob = 0; ob < outer; ++ob)
                {
                    for (size_t ij = 0; ij < inner; ++ij)
                    {
                        size_t srcOff = ob * (size_t)dimAxis * inner + (size_t)u * inner + ij;
                        flat[(size_t)u * S + wrote] = static_cast<WT>(inPtr[srcOff]);
                        ++wrote;
                    }
                }
            }

            using Pair = std::pair<int, size_t>; // (original index, offset into flat)
            std::vector<Pair> keyed(A);
            for (int u = 0; u < A; ++u)
                keyed[u] = {u, (size_t)u * S};

            auto lessLex = [&](size_t aoff, size_t boff){
                const WT* pa = &flat[aoff];
                const WT* pb = &flat[boff];
                for (size_t t = 0; t < S; ++t) {
                    if (pa[t] < pb[t]) return true;
                    if (pa[t] > pb[t]) return false;
                }
                return false;
            };
            auto equalLex = [&](size_t aoff, size_t boff){
                const WT* pa = &flat[aoff];
                const WT* pb = &flat[boff];
                for (size_t t = 0; t < S; ++t) {
                    if (pa[t] != pb[t]) return false;