class StringFunctions {

    @Description("Translate characters from the source string based on original and translations strings")
    @ScalarFunction
    @LiteralParameters({"x", "y", "z"})
    @SqlType(StandardTypes.VARCHAR)
    public static Slice translate(@SqlType("varchar(x)") Slice source, @SqlType("varchar(y)") Slice from, @SqlType("varchar(z)") Slice to)
    {
        int[] fromCodePoints = castToCodePoints(from);
        int[] toCodePoints = castToCodePoints(to);

        Int2IntOpenHashMap map = new Int2IntOpenHashMap(fromCodePoints.length);
        for (int index = 0; index < fromCodePoints.length; index++) {
            int fromCodePoint = fromCodePoints[index];
            map.putIfAbsent(fromCodePoint, index < toCodePoints.length ? toCodePoints[index] : -1);
        }

        int[] sourceCodePoints = castToCodePoints(source);
        int[] targetCodePoints = new int[sourceCodePoints.length];
        int targetPositions = 0;
        int targetBytes = 0;
        for (int index = 0; index < sourceCodePoints.length; index++) {
            int codePoint = sourceCodePoints[index];
            if (map.containsKey(codePoint)) {
                int translatedCodePoint = map.get(codePoint);
                if (translatedCodePoint == -1) {
                    continue;
                }
                codePoint = translatedCodePoint;
            }
            targetCodePoints[targetPositions++] = codePoint;
            targetBytes += lengthOfCodePoint(codePoint);
        }

        Slice target = Slices.allocate(targetBytes);
        int offset = 0;
        for (int index = 0; index < targetPositions; index++) {
            offset += setCodePointAt(targetCodePoints[index], target, offset);
        }

        return target;
    }

    private  StringFunctions();

}