aboutsummaryrefslogtreecommitdiffstats
path: root/vespajlib/src/main/java/com/yahoo/text/DataTypeIdentifier.java
blob: 90e85cbb30c4844ea0f94ee511edf3abbb146a25 (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.text;

/**
 * @author baldersheim
 */
public class DataTypeIdentifier {

    private static final byte [] ARRAY = {'a', 'r', 'r', 'a', 'y'};
    private static final byte [] ANNOTATIONREFERENCE = {'a','n','n','o','t','a','t','i','o','n','r','e','f','e','r','e','n','c','e'};
    private static final byte [] MAP = { 'm', 'a', 'p'};
    private static final byte [] WSET = {'w', 'e', 'i', 'g', 'h', 't', 'e', 'd', 's', 'e', 't'};
    private static final byte [] CREATEIFNONEXISTENT = {';','a', 'd', 'd'};
    private static final byte [] REMOVEIFZERO = {';','r', 'e', 'm', 'o', 'v', 'e'};
    private static final byte [] CREATANDREMOVE = {';','a', 'd', 'd',';','r', 'e', 'm', 'o', 'v', 'e'};
    private static final byte [] EMPTY = {};
    private Utf8String utf8;
    public DataTypeIdentifier(String s) {
        utf8 = new Utf8String(s);
        verify(utf8.wrap().array());
    }
    public DataTypeIdentifier(AbstractUtf8Array utf8) {
        this.utf8 = new Utf8String(utf8);
        verify(utf8.wrap().array());
    }
    public DataTypeIdentifier(byte [] utf8) {
        this(new Utf8Array(utf8));
    }

    private DataTypeIdentifier(final byte [] prefix, DataTypeIdentifier nested, final byte [] postfix) {
        utf8 = new Utf8String(new Utf8Array(createPrefixDataType(prefix, nested, postfix)));
    }
    private DataTypeIdentifier(final byte [] prefix, DataTypeIdentifier key, DataTypeIdentifier value) {
        utf8 = new Utf8String(new Utf8Array(createMapDataType(prefix, key, value)));
    }

    public static DataTypeIdentifier createArrayDataTypeIdentifier(DataTypeIdentifier nested) {
        return new DataTypeIdentifier(ARRAY, nested, EMPTY);
    }
    public static DataTypeIdentifier createAnnotationReferenceDataTypeIdentifier(DataTypeIdentifier nested) {
        return new DataTypeIdentifier(ANNOTATIONREFERENCE, nested, EMPTY);
    }
    public static DataTypeIdentifier createMapDataTypeIdentifier(DataTypeIdentifier key, DataTypeIdentifier value) {
        return new DataTypeIdentifier(MAP, key, value);
    }
    public static DataTypeIdentifier createWeightedSetTypeIdentifier(DataTypeIdentifier nested, boolean createIfNonExistent, boolean removeIfZero) {
        return new DataTypeIdentifier(WSET, nested, createPostfix(createIfNonExistent, removeIfZero));
    }
    @Override
    public int hashCode() {
        return utf8.hashCode();
    }
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof DataTypeIdentifier) {
            return utf8.equals(((DataTypeIdentifier)obj).utf8);
        }
        return false;
    }
    @Override
    public String toString() {
        return utf8.toString();
    }
    public final Utf8String getUtf8() {
        return utf8;
    }
    private static byte [] createPostfix(boolean createIfNonExistent, boolean removeIfZero) {
        if (createIfNonExistent && removeIfZero) {
            return CREATANDREMOVE;
        } else if (createIfNonExistent) {
            return CREATEIFNONEXISTENT;
        } else if (removeIfZero) {
            return REMOVEIFZERO;
        }
        return EMPTY;
    }
    private static byte [] createPrefixDataType(final byte [] prefix, final DataTypeIdentifier nested, final byte [] postfix) {
        byte [] whole = new byte[prefix.length + 2 + nested.utf8.getByteLength() + postfix.length];
        for (int i=0; i < prefix.length; i++) {
            whole[i] = prefix[i];
        }
        whole[prefix.length] = '<';
        for (int i = 0, m=nested.utf8.getByteLength(); i < m; i++ ) {
            whole[prefix.length+1+i] = nested.utf8.getByte(i);
        }
        whole[prefix.length + 1 + nested.utf8.getByteLength()] = '>';
        for (int i = 0; i < postfix.length; i++) {
            whole[prefix.length + 1 + nested.utf8.length() + 1 + i] = postfix[i];
        }
        return whole;
    }
    private static byte [] createMapDataType(final byte [] prefix, final DataTypeIdentifier key, final DataTypeIdentifier value) {
        byte [] whole = new byte[prefix.length + 3 + key.utf8.getByteLength() + value.utf8.getByteLength()];
        for (int i=0; i < prefix.length; i++) {
            whole[i] = prefix[i];
        }
        whole[prefix.length] = '<';
        for (int i = 0, m=key.utf8.getByteLength(); i < m; i++ ) {
            whole[prefix.length+1+i] = key.utf8.getByte(i);
        }
        whole[prefix.length + 1 + key.utf8.getByteLength()] = ',';
        for (int i = 0; i < value.utf8.getByteLength(); i++) {
            whole[prefix.length + 1 + key.utf8.getByteLength() + 1 + i] = value.utf8.getByte(i);
        }
        whole[whole.length-1] = '>';
        return whole;
    }
    private static byte [] verify(final byte [] utf8) {
        if (utf8.length > 0) {
            verifyFirst(utf8[0], utf8);
            for (int i=1; i < utf8.length; i++) {
                verifyAny(utf8[i], utf8);
            }
        }
        return utf8;

    }
    private static boolean verifyFirst(byte c, byte [] identifier) {
        if (!((c == '_')  || ((c >= 'a') && (c <= 'z')))) {
            throw new IllegalArgumentException("Illegal starting character '" + (char)c + "' of identifier '" + new Utf8String(new Utf8Array(identifier)).toString() +"'.");
        }
        return true;
    }
    private static boolean verifyAny(byte c, byte [] identifier) {
        if (!((c == '_') || (c == '.') || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9')))) {
            throw new IllegalArgumentException("Illegal character '" + (char)c + "' of identifier '" + new Utf8String(new Utf8Array(identifier)).toString() +"'.");
        }
        return true;
    }

}