1
1
package eu .ostrzyciel .jelly .core ;
2
2
3
+ import eu .ostrzyciel .jelly .core .internal .RowBufferAppender ;
3
4
import eu .ostrzyciel .jelly .core .proto .v1 .*;
4
5
import scala .collection .mutable .Buffer ;
5
6
6
7
import java .util .LinkedHashMap ;
8
+ import java .util .function .Consumer ;
7
9
import java .util .function .Function ;
8
10
9
11
/**
10
12
* Encodes RDF nodes native to the used RDF library (e.g., Apache Jena, RDF4J) into Jelly's protobuf objects.
11
13
* This class performs a lot of caching to avoid encoding the same node multiple times. It is absolutely NOT
12
14
* thread-safe, and should only be ever used by a single instance of ProtoEncoder.
13
- *
14
- * <p>
15
- * This class is marked as public because make* methods in ProtoEncoder are inlined, and the inlining
16
- * requires the NodeEncoder to be public. Do NOT use this class outside of ProtoEncoder. It is not
17
- * considered part of the public API.
18
- * </p>
15
+ *
19
16
* @param <TNode> The type of RDF nodes used by the RDF library.
20
17
*/
21
- public final class NodeEncoder <TNode > {
18
+ final class NodeEncoder <TNode > {
22
19
/**
23
20
* A cached node that depends on other lookups (RdfIri and RdfLiteral in the datatype variant).
24
21
*/
@@ -61,6 +58,8 @@ protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
61
58
private final EncoderLookup prefixLookup ;
62
59
private final EncoderLookup nameLookup ;
63
60
61
+ private final RowBufferAppender bufferAppender ;
62
+
64
63
// We split the node caches in three – the first two are for nodes that depend on the lookups
65
64
// (IRIs and datatype literals). The third one is for nodes that don't depend on the lookups.
66
65
private final NodeCache <Object , DependentNode > iriNodeCache ;
@@ -75,11 +74,18 @@ protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
75
74
/**
76
75
* Creates a new NodeEncoder.
77
76
* @param opt Jelly RDF stream options
77
+ * @param bufferAppender consumer of the lookup entry rows
78
78
* @param nodeCacheSize The size of the node cache (for nodes that don't depend on lookups)
79
79
* @param iriNodeCacheSize The size of the IRI dependent node cache (for prefix+name encoding)
80
80
* @param dtLiteralNodeCacheSize The size of the datatype literal dependent node cache
81
81
*/
82
- public NodeEncoder (RdfStreamOptions opt , int nodeCacheSize , int iriNodeCacheSize , int dtLiteralNodeCacheSize ) {
82
+ public NodeEncoder (
83
+ RdfStreamOptions opt ,
84
+ RowBufferAppender bufferAppender ,
85
+ int nodeCacheSize ,
86
+ int iriNodeCacheSize ,
87
+ int dtLiteralNodeCacheSize
88
+ ) {
83
89
datatypeLookup = new EncoderLookup (opt .maxDatatypeTableSize (), true );
84
90
this .maxPrefixTableSize = opt .maxPrefixTableSize ();
85
91
if (maxPrefixTableSize > 0 ) {
@@ -96,18 +102,18 @@ public NodeEncoder(RdfStreamOptions opt, int nodeCacheSize, int iriNodeCacheSize
96
102
dtLiteralNodeCache = new NodeCache <>(dtLiteralNodeCacheSize );
97
103
nameLookup = new EncoderLookup (opt .maxNameTableSize (), maxPrefixTableSize > 0 );
98
104
nodeCache = new NodeCache <>(nodeCacheSize );
105
+ this .bufferAppender = bufferAppender ;
99
106
}
100
107
101
108
/**
102
109
* Encodes a datatype literal using two layers of caching – both for the entire literal, and the datatype name.
103
110
* @param key The literal key (the unencoded literal node)
104
111
* @param lex The lexical form of the literal
105
112
* @param datatypeName The name of the datatype
106
- * @param rowsBuffer The buffer to which the new datatype entry should be appended
107
113
* @return The encoded literal
108
114
*/
109
115
public UniversalTerm encodeDtLiteral (
110
- TNode key , String lex , String datatypeName , Buffer < RdfStreamRow > rowsBuffer
116
+ TNode key , String lex , String datatypeName
111
117
) {
112
118
var cachedNode = dtLiteralNodeCache .computeIfAbsent (key , k -> new DependentNode ());
113
119
// Check if the value is still valid
@@ -121,15 +127,13 @@ public UniversalTerm encodeDtLiteral(
121
127
// The node is not encoded, but we may already have the datatype encoded
122
128
var dtEntry = datatypeLookup .getOrAddEntry (datatypeName );
123
129
if (dtEntry .newEntry ) {
124
- rowsBuffer .append (new RdfStreamRow (
125
- new RdfDatatypeEntry (dtEntry .setId , datatypeName )
126
- ));
130
+ bufferAppender .appendLookupEntry (new RdfDatatypeEntry (dtEntry .setId , datatypeName ));
127
131
}
128
132
int dtId = dtEntry .getId ;
129
133
cachedNode .lookupPointer1 = dtId ;
130
134
cachedNode .lookupSerial1 = datatypeLookup .serials [dtId ];
131
135
cachedNode .encoded = new RdfLiteral (
132
- lex , new RdfLiteral$LiteralKind$Datatype (dtId )
136
+ lex , new RdfLiteral$LiteralKind$Datatype (dtId )
133
137
);
134
138
135
139
return cachedNode .encoded ;
@@ -138,17 +142,14 @@ public UniversalTerm encodeDtLiteral(
138
142
/**
139
143
* Encodes an IRI using two layers of caching – both for the entire IRI, and the prefix and name tables.
140
144
* @param iri The IRI to encode
141
- * @param rowsBuffer The buffer to which the new name and prefix lookup entries should be appended
142
145
* @return The encoded IRI
143
146
*/
144
- public UniversalTerm encodeIri (String iri , Buffer < RdfStreamRow > rowsBuffer ) {
147
+ public UniversalTerm encodeIri (String iri ) {
145
148
if (maxPrefixTableSize == 0 ) {
146
149
// Fast path for no prefixes
147
150
var nameEntry = nameLookup .getOrAddEntry (iri );
148
151
if (nameEntry .newEntry ) {
149
- rowsBuffer .append (new RdfStreamRow (
150
- new RdfNameEntry (nameEntry .setId , iri )
151
- ));
152
+ bufferAppender .appendLookupEntry (new RdfNameEntry (nameEntry .setId , iri ));
152
153
}
153
154
int nameId = nameEntry .getId ;
154
155
if (lastIriNameId + 1 == nameId ) {
@@ -192,14 +193,10 @@ public UniversalTerm encodeIri(String iri, Buffer<RdfStreamRow> rowsBuffer) {
192
193
var prefixEntry = prefixLookup .getOrAddEntry (prefix );
193
194
var nameEntry = nameLookup .getOrAddEntry (postfix );
194
195
if (prefixEntry .newEntry ) {
195
- rowsBuffer .append (new RdfStreamRow (
196
- new RdfPrefixEntry (prefixEntry .setId , prefix )
197
- ));
196
+ bufferAppender .appendLookupEntry (new RdfPrefixEntry (prefixEntry .setId , prefix ));
198
197
}
199
198
if (nameEntry .newEntry ) {
200
- rowsBuffer .append (new RdfStreamRow (
201
- new RdfNameEntry (nameEntry .setId , postfix )
202
- ));
199
+ bufferAppender .appendLookupEntry (new RdfNameEntry (nameEntry .setId , postfix ));
203
200
}
204
201
int nameId = nameEntry .getId ;
205
202
int prefixId = prefixEntry .getId ;
0 commit comments