@@ -98,11 +98,19 @@ public enum INPUT_TYPE {
9898 */
9999 static final byte ARCS_FOR_DIRECT_ADDRESSING = 1 << 6 ;
100100
101+ /**
102+ * Value of the arc flags to declare a node with continuous arcs designed for pos the arc directly
103+ * with labelToPos - firstLabel. like {@link #ARCS_FOR_BINARY_SEARCH} we use flag combinations
104+ * that will not occur at the same time.
105+ */
106+ static final byte ARCS_FOR_CONTINUOUS = ARCS_FOR_DIRECT_ADDRESSING + ARCS_FOR_BINARY_SEARCH ;
107+
101108 // Increment version to change it
102109 private static final String FILE_FORMAT_NAME = "FST" ;
103110 private static final int VERSION_START = 6 ;
104111 private static final int VERSION_LITTLE_ENDIAN = 8 ;
105- static final int VERSION_CURRENT = VERSION_LITTLE_ENDIAN ;
112+ private static final int VERSION_CONTINUOUS_ARCS = 9 ;
113+ static final int VERSION_CURRENT = VERSION_CONTINUOUS_ARCS ;
106114
107115 // Never serialized; just used to represent the virtual
108116 // final node w/ no arcs:
@@ -243,7 +251,10 @@ public String toString() {
243251 .append (numArcs ())
244252 .append (")" )
245253 .append ("(" )
246- .append (nodeFlags () == ARCS_FOR_DIRECT_ADDRESSING ? "da" : "bs" )
254+ .append (
255+ nodeFlags () == ARCS_FOR_DIRECT_ADDRESSING
256+ ? "da"
257+ : nodeFlags () == ARCS_FOR_CONTINUOUS ? "cs" : "bs" )
247258 .append (")" );
248259 }
249260 return b .toString ();
@@ -285,8 +296,8 @@ public int arcIdx() {
285296
286297 /**
287298 * Node header flags. Only meaningful to check if the value is either {@link
288- * #ARCS_FOR_BINARY_SEARCH} or {@link #ARCS_FOR_DIRECT_ADDRESSING} (other value when bytesPerArc
289- * == 0).
299+ * #ARCS_FOR_BINARY_SEARCH} or {@link #ARCS_FOR_DIRECT_ADDRESSING} or {@link
300+ * #ARCS_FOR_CONTINUOUS} (other value when bytesPerArc == 0).
290301 */
291302 public byte nodeFlags () {
292303 return nodeFlags ;
@@ -318,7 +329,7 @@ public int numArcs() {
318329
319330 /**
320331 * First label of a direct addressing node. Only valid if nodeFlags == {@link
321- * #ARCS_FOR_DIRECT_ADDRESSING}.
332+ * #ARCS_FOR_DIRECT_ADDRESSING} or {@link #ARCS_FOR_CONTINUOUS} .
322333 */
323334 int firstLabel () {
324335 return firstLabel ;
@@ -653,7 +664,9 @@ Arc<T> readLastTargetArc(Arc<T> follow, Arc<T> arc, BytesReader in) throws IOExc
653664 } else {
654665 in .setPosition (follow .target ());
655666 byte flags = arc .nodeFlags = in .readByte ();
656- if (flags == ARCS_FOR_BINARY_SEARCH || flags == ARCS_FOR_DIRECT_ADDRESSING ) {
667+ if (flags == ARCS_FOR_BINARY_SEARCH
668+ || flags == ARCS_FOR_DIRECT_ADDRESSING
669+ || flags == ARCS_FOR_CONTINUOUS ) {
657670 // Special arc which is actually a node header for fixed length arcs.
658671 // Jump straight to end to find the last arc.
659672 arc .numArcs = in .readVInt ();
@@ -664,10 +677,14 @@ Arc<T> readLastTargetArc(Arc<T> follow, Arc<T> arc, BytesReader in) throws IOExc
664677 arc .firstLabel = readLabel (in );
665678 arc .posArcsStart = in .getPosition ();
666679 readLastArcByDirectAddressing (arc , in );
667- } else {
680+ } else if ( flags == ARCS_FOR_BINARY_SEARCH ) {
668681 arc .arcIdx = arc .numArcs () - 2 ;
669682 arc .posArcsStart = in .getPosition ();
670683 readNextRealArc (arc , in );
684+ } else {
685+ arc .firstLabel = readLabel (in );
686+ arc .posArcsStart = in .getPosition ();
687+ readLastArcByContinuous (arc , in );
671688 }
672689 } else {
673690 arc .flags = flags ;
@@ -740,7 +757,9 @@ private void readFirstArcInfo(long nodeAddress, Arc<T> arc, final BytesReader in
740757 in .setPosition (nodeAddress );
741758
742759 byte flags = arc .nodeFlags = in .readByte ();
743- if (flags == ARCS_FOR_BINARY_SEARCH || flags == ARCS_FOR_DIRECT_ADDRESSING ) {
760+ if (flags == ARCS_FOR_BINARY_SEARCH
761+ || flags == ARCS_FOR_DIRECT_ADDRESSING
762+ || flags == ARCS_FOR_CONTINUOUS ) {
744763 // Special arc which is actually a node header for fixed length arcs.
745764 arc .numArcs = in .readVInt ();
746765 arc .bytesPerArc = in .readVInt ();
@@ -749,6 +768,8 @@ private void readFirstArcInfo(long nodeAddress, Arc<T> arc, final BytesReader in
749768 readPresenceBytes (arc , in );
750769 arc .firstLabel = readLabel (in );
751770 arc .presenceIndex = -1 ;
771+ } else if (flags == ARCS_FOR_CONTINUOUS ) {
772+ arc .firstLabel = readLabel (in );
752773 }
753774 arc .posArcsStart = in .getPosition ();
754775 } else {
@@ -773,7 +794,9 @@ boolean isExpandedTarget(Arc<T> follow, BytesReader in) throws IOException {
773794 } else {
774795 in .setPosition (follow .target ());
775796 byte flags = in .readByte ();
776- return flags == ARCS_FOR_BINARY_SEARCH || flags == ARCS_FOR_DIRECT_ADDRESSING ;
797+ return flags == ARCS_FOR_BINARY_SEARCH
798+ || flags == ARCS_FOR_DIRECT_ADDRESSING
799+ || flags == ARCS_FOR_CONTINUOUS ;
777800 }
778801 }
779802
@@ -801,16 +824,18 @@ int readNextArcLabel(Arc<T> arc, BytesReader in) throws IOException {
801824
802825 in .setPosition (arc .nextArc ());
803826 byte flags = in .readByte ();
804- if (flags == ARCS_FOR_BINARY_SEARCH || flags == ARCS_FOR_DIRECT_ADDRESSING ) {
827+ if (flags == ARCS_FOR_BINARY_SEARCH
828+ || flags == ARCS_FOR_DIRECT_ADDRESSING
829+ || flags == ARCS_FOR_CONTINUOUS ) {
805830 // System.out.println(" nextArc fixed length arc");
806831 // Special arc which is actually a node header for fixed length arcs.
807832 int numArcs = in .readVInt ();
808833 in .readVInt (); // Skip bytesPerArc.
809834 if (flags == ARCS_FOR_BINARY_SEARCH ) {
810835 in .readByte (); // Skip arc flags.
811- } else {
836+ } else if ( flags == ARCS_FOR_DIRECT_ADDRESSING ) {
812837 in .skipBytes (getNumPresenceBytes (numArcs ));
813- }
838+ } // Nothing to do for ARCS_FOR_CONTINUOUS
814839 }
815840 } else {
816841 switch (arc .nodeFlags ()) {
@@ -826,6 +851,8 @@ int readNextArcLabel(Arc<T> arc, BytesReader in) throws IOException {
826851 int nextIndex = BitTable .nextBitSet (arc .arcIdx (), arc , in );
827852 assert nextIndex != -1 ;
828853 return arc .firstLabel () + nextIndex ;
854+ case ARCS_FOR_CONTINUOUS :
855+ return arc .firstLabel () + arc .arcIdx () + 1 ;
829856 default :
830857 // Variable length arcs - linear search.
831858 assert arc .bytesPerArc () == 0 ;
@@ -849,6 +876,20 @@ public Arc<T> readArcByIndex(Arc<T> arc, final BytesReader in, int idx) throws I
849876 return readArc (arc , in );
850877 }
851878
879+ /**
880+ * Reads a Continuous node arc, with the provided index in the label range.
881+ *
882+ * @param rangeIndex The index of the arc in the label range. It must be within the label range.
883+ */
884+ public Arc <T > readArcByContinuous (Arc <T > arc , final BytesReader in , int rangeIndex )
885+ throws IOException {
886+ assert rangeIndex >= 0 && rangeIndex < arc .numArcs ();
887+ in .setPosition (arc .posArcsStart () - rangeIndex * (long ) arc .bytesPerArc ());
888+ arc .arcIdx = rangeIndex ;
889+ arc .flags = in .readByte ();
890+ return readArc (arc , in );
891+ }
892+
852893 /**
853894 * Reads a present direct addressing node arc, with the provided index in the label range.
854895 *
@@ -888,6 +929,11 @@ public Arc<T> readLastArcByDirectAddressing(Arc<T> arc, final BytesReader in) th
888929 return readArcByDirectAddressing (arc , in , arc .numArcs () - 1 , presenceIndex );
889930 }
890931
932+ /** Reads the last arc of a continuous node. */
933+ public Arc <T > readLastArcByContinuous (Arc <T > arc , final BytesReader in ) throws IOException {
934+ return readArcByContinuous (arc , in , arc .numArcs () - 1 );
935+ }
936+
891937 /** Never returns null, but you should never call this if arc.isLast() is true. */
892938 public Arc <T > readNextRealArc (Arc <T > arc , final BytesReader in ) throws IOException {
893939
@@ -896,6 +942,7 @@ public Arc<T> readNextRealArc(Arc<T> arc, final BytesReader in) throws IOExcepti
896942
897943 switch (arc .nodeFlags ()) {
898944 case ARCS_FOR_BINARY_SEARCH :
945+ case ARCS_FOR_CONTINUOUS :
899946 assert arc .bytesPerArc () > 0 ;
900947 arc .arcIdx ++;
901948 assert arc .arcIdx () >= 0 && arc .arcIdx () < arc .numArcs ();
@@ -924,7 +971,7 @@ public Arc<T> readNextRealArc(Arc<T> arc, final BytesReader in) throws IOExcepti
924971 * positioned just after the arc flags byte.
925972 */
926973 private Arc <T > readArc (Arc <T > arc , BytesReader in ) throws IOException {
927- if (arc .nodeFlags () == ARCS_FOR_DIRECT_ADDRESSING ) {
974+ if (arc .nodeFlags () == ARCS_FOR_DIRECT_ADDRESSING || arc . nodeFlags () == ARCS_FOR_CONTINUOUS ) {
928975 arc .label = arc .firstLabel () + arc .arcIdx ();
929976 } else {
930977 arc .label = readLabel (in );
@@ -1067,6 +1114,17 @@ public Arc<T> findTargetArc(int labelToMatch, Arc<T> follow, Arc<T> arc, BytesRe
10671114 }
10681115 }
10691116 return null ;
1117+ } else if (flags == ARCS_FOR_CONTINUOUS ) {
1118+ arc .numArcs = in .readVInt ();
1119+ arc .bytesPerArc = in .readVInt ();
1120+ arc .firstLabel = readLabel (in );
1121+ arc .posArcsStart = in .getPosition ();
1122+ int arcIndex = labelToMatch - arc .firstLabel ();
1123+ if (arcIndex < 0 || arcIndex >= arc .numArcs ()) {
1124+ return null ; // Before or after label range.
1125+ }
1126+ arc .arcIdx = arcIndex - 1 ;
1127+ return readNextRealArc (arc , in );
10701128 }
10711129
10721130 // Linear scan
0 commit comments