@@ -260,6 +260,34 @@ object ByteString {
260260 }
261261 }
262262
263+ override def lastIndexOf [B >: Byte ](elem : B ): Int = lastIndexOf(elem, length - 1 )
264+ override def lastIndexOf [B >: Byte ](elem : B , end : Int ): Int = {
265+ if (end < 0 ) - 1
266+ else {
267+ var found = - 1
268+ var i = math.min(end, length - 1 )
269+ while (i >= 0 && found == - 1 ) {
270+ if (bytes(i) == elem) found = i
271+ i -= 1
272+ }
273+ found
274+ }
275+ }
276+
277+ override def lastIndexOf (elem : Byte ): Int = lastIndexOf(elem, length - 1 )
278+ override def lastIndexOf (elem : Byte , end : Int ): Int = {
279+ if (end < 0 ) - 1
280+ else {
281+ var found = - 1
282+ var i = math.min(end, length - 1 )
283+ while (i >= 0 && found == - 1 ) {
284+ if (bytes(i) == elem) found = i
285+ i -= 1
286+ }
287+ found
288+ }
289+ }
290+
263291 override def slice (from : Int , until : Int ): ByteString =
264292 if (from <= 0 && until >= length) this
265293 else if (from >= length || until <= 0 || from >= until) ByteString .empty
@@ -461,6 +489,34 @@ object ByteString {
461489 }
462490 }
463491
492+ override def lastIndexOf [B >: Byte ](elem : B ): Int = lastIndexOf(elem, length - 1 )
493+ override def lastIndexOf [B >: Byte ](elem : B , end : Int ): Int = {
494+ if (end < 0 ) - 1
495+ else {
496+ var found = - 1
497+ var i = math.min(end, length - 1 )
498+ while (i >= 0 && found == - 1 ) {
499+ if (bytes(startIndex + i) == elem) found = i
500+ i -= 1
501+ }
502+ found
503+ }
504+ }
505+
506+ override def lastIndexOf (elem : Byte ): Int = lastIndexOf(elem, length - 1 )
507+ override def lastIndexOf (elem : Byte , end : Int ): Int = {
508+ if (end < 0 ) - 1
509+ else {
510+ var found = - 1
511+ var i = math.min(end, length - 1 )
512+ while (i >= 0 && found == - 1 ) {
513+ if (bytes(startIndex + i) == elem) found = i
514+ i -= 1
515+ }
516+ found
517+ }
518+ }
519+
464520 protected def writeReplace (): AnyRef = new SerializationProxy (this )
465521
466522 override def toArrayUnsafe (): Array [Byte ] = {
@@ -707,7 +763,7 @@ object ByteString {
707763 else {
708764 val bs = bytestrings(bsIdx)
709765
710- if (bs.length <= relativeIndex) {
766+ if (bs.length <= relativeIndex || bs.isEmpty ) {
711767 find(bsIdx + 1 , relativeIndex - bs.length, bytesPassed + bs.length)
712768 } else {
713769 val subIndexOf = bs.indexOf(elem, relativeIndex)
@@ -734,7 +790,7 @@ object ByteString {
734790 else {
735791 val bs = bytestrings(bsIdx)
736792
737- if (bs.length <= relativeIndex) {
793+ if (bs.length <= relativeIndex || bs.isEmpty ) {
738794 find(bsIdx + 1 , relativeIndex - bs.length, bytesPassed + bs.length)
739795 } else {
740796 val subIndexOf = bs.indexOf(elem, relativeIndex)
@@ -749,6 +805,69 @@ object ByteString {
749805 }
750806 }
751807
808+ override def lastIndexOf [B >: Byte ](elem : B ): Int = lastIndexOf(elem, length - 1 )
809+ override def lastIndexOf [B >: Byte ](elem : B , end : Int ): Int = {
810+ if (end < 0 ) - 1
811+ else {
812+ val byteStringsLast = bytestrings.size - 1
813+
814+ @ tailrec
815+ def find (bsIdx : Int , relativeIndex : Int , len : Int ): Int = {
816+ if (bsIdx < 0 ) - 1
817+ else {
818+ val bs = bytestrings(bsIdx)
819+ val bsStartIndex = len - bs.length
820+
821+ if (relativeIndex < bsStartIndex || bs.isEmpty) {
822+ if (bsIdx == 0 ) - 1
823+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
824+ } else {
825+ val subIndexOf = bs.lastIndexOf(elem, relativeIndex)
826+ if (subIndexOf < 0 ) {
827+ if (bsIdx == 0 ) - 1
828+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
829+ } else subIndexOf + bsStartIndex
830+ }
831+ }
832+ }
833+
834+ find(byteStringsLast, math.min(end, length), length)
835+ }
836+ }
837+
838+ override def lastIndexOf (elem : Byte ): Int = lastIndexOf(elem, length - 1 )
839+ override def lastIndexOf (elem : Byte , end : Int ): Int = {
840+ if (end < 0 ) - 1
841+ else {
842+ if (end < 0 ) - 1
843+ else {
844+ val byteStringsLast = bytestrings.size - 1
845+
846+ @ tailrec
847+ def find (bsIdx : Int , relativeIndex : Int , len : Int ): Int = {
848+ if (bsIdx < 0 ) - 1
849+ else {
850+ val bs = bytestrings(bsIdx)
851+ val bsStartIndex = len - bs.length
852+
853+ if (relativeIndex < bsStartIndex || bs.isEmpty) {
854+ if (bsIdx == 0 ) - 1
855+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
856+ } else {
857+ val subIndexOf = bs.lastIndexOf(elem, relativeIndex)
858+ if (subIndexOf < 0 ) {
859+ if (bsIdx == 0 ) - 1
860+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
861+ } else subIndexOf + bsStartIndex
862+ }
863+ }
864+ }
865+
866+ find(byteStringsLast, math.min(end, length), length)
867+ }
868+ }
869+ }
870+
752871 protected def writeReplace (): AnyRef = new SerializationProxy (this )
753872 }
754873
@@ -846,7 +965,7 @@ sealed abstract class ByteString extends IndexedSeq[Byte] with IndexedSeqOptimiz
846965 // optimized in subclasses
847966 override def indexOf [B >: Byte ](elem : B ): Int = indexOf[B ](elem, 0 )
848967
849- // optimized version of indexOf for bytes, implemented in subclasses
968+ // optimized versions of indexOf and lastIndexOf for bytes, optimized in subclasses
850969 /**
851970 * Finds index of first occurrence of some byte in this ByteString after or at some start index.
852971 *
@@ -866,12 +985,37 @@ sealed abstract class ByteString extends IndexedSeq[Byte] with IndexedSeqOptimiz
866985 * Similar to indexOf, but it avoids boxing if the value is already a byte.
867986 *
868987 * @param elem the element value to search for.
869- * @return the index `>= from` of the first element of this ByteString that is equal (as determined by `==`)
988+ * @return the index of the first element of this ByteString that is equal (as determined by `==`)
870989 * to `elem`, or `-1`, if none exists.
871990 * @since 1.1.0
872991 */
873992 def indexOf (elem : Byte ): Int = indexOf(elem, 0 )
874993
994+ /**
995+ * Finds index of last occurrence of some byte in this ByteString before or at some end index.
996+ *
997+ * Similar to lastIndexOf, but it avoids boxing if the value is already a byte.
998+ *
999+ * @param elem the element value to search for.
1000+ * @param end the end index
1001+ * @return the index `<= end` of the last element of this ByteString that is equal (as determined by `==`)
1002+ * to `elem`, or `-1`, if none exists.
1003+ * @since 2.0.0
1004+ */
1005+ def lastIndexOf (elem : Byte , end : Int ): Int = lastIndexOf[Byte ](elem, end)
1006+
1007+ /**
1008+ * Finds index of last occurrence of some byte in this ByteString.
1009+ *
1010+ * Similar to lastIndexOf, but it avoids boxing if the value is already a byte.
1011+ *
1012+ * @param elem the element value to search for.
1013+ * @return the index of the last element of this ByteString that is equal (as determined by `==`)
1014+ * to `elem`, or `-1`, if none exists.
1015+ * @since 2.0.0
1016+ */
1017+ def lastIndexOf (elem : Byte ): Int = lastIndexOf(elem, length - 1 )
1018+
8751019 override def grouped (size : Int ): Iterator [ByteString ] = {
8761020 if (size <= 0 ) {
8771021 throw new IllegalArgumentException (s " size= $size must be positive " )
0 commit comments