@@ -314,6 +314,32 @@ object ByteString {
314314 else - 1
315315 }
316316
317+ override def lastIndexOf [B >: Byte ](elem : B , end : Int ): Int = {
318+ if (end < 0 ) - 1
319+ else {
320+ var found = - 1
321+ var i = math.min(end, length - 1 )
322+ while (i >= 0 && found == - 1 ) {
323+ if (bytes(i) == elem) found = i
324+ i -= 1
325+ }
326+ found
327+ }
328+ }
329+
330+ override def lastIndexOf (elem : Byte , end : Int ): Int = {
331+ if (end < 0 ) - 1
332+ else {
333+ var found = - 1
334+ var i = math.min(end, length - 1 )
335+ while (i >= 0 && found == - 1 ) {
336+ if (bytes(i) == elem) found = i
337+ i -= 1
338+ }
339+ found
340+ }
341+ }
342+
317343 override def slice (from : Int , until : Int ): ByteString =
318344 if (from <= 0 && until >= length) this
319345 else if (from >= length || until <= 0 || from >= until) ByteString .empty
@@ -554,7 +580,6 @@ object ByteString {
554580 i += 1
555581 }
556582 - 1
557-
558583 }
559584
560585 // the calling code already adds the startIndex so this method does not need to
@@ -575,6 +600,32 @@ object ByteString {
575600 else - 1
576601 }
577602
603+ override def lastIndexOf [B >: Byte ](elem : B , end : Int ): Int = {
604+ if (end < 0 ) - 1
605+ else {
606+ var found = - 1
607+ var i = math.min(end, length - 1 )
608+ while (i >= 0 && found == - 1 ) {
609+ if (bytes(startIndex + i) == elem) found = i
610+ i -= 1
611+ }
612+ found
613+ }
614+ }
615+
616+ override def lastIndexOf (elem : Byte , end : Int ): Int = {
617+ if (end < 0 ) - 1
618+ else {
619+ var found = - 1
620+ var i = math.min(end, length - 1 )
621+ while (i >= 0 && found == - 1 ) {
622+ if (bytes(startIndex + i) == elem) found = i
623+ i -= 1
624+ }
625+ found
626+ }
627+ }
628+
578629 override def copyToArray [B >: Byte ](dest : Array [B ], start : Int , len : Int ): Int = {
579630 // min of the bytes available to copy, bytes there is room for in dest and the requested number of bytes
580631 val toCopy = math.min(math.min(len, length), dest.length - start)
@@ -895,6 +946,67 @@ object ByteString {
895946 }
896947 }
897948
949+ override def lastIndexOf [B >: Byte ](elem : B , end : Int ): Int = {
950+ if (end < 0 ) - 1
951+ else {
952+ val byteStringsLast = bytestrings.size - 1
953+
954+ @ tailrec
955+ def find (bsIdx : Int , relativeIndex : Int , len : Int ): Int = {
956+ if (bsIdx < 0 ) - 1
957+ else {
958+ val bs = bytestrings(bsIdx)
959+ val bsStartIndex = len - bs.length
960+
961+ if (relativeIndex < bsStartIndex || bs.isEmpty) {
962+ if (bsIdx == 0 ) - 1
963+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
964+ } else {
965+ val subIndexOf = bs.lastIndexOf(elem, relativeIndex)
966+ if (subIndexOf < 0 ) {
967+ if (bsIdx == 0 ) - 1
968+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
969+ } else subIndexOf + bsStartIndex
970+ }
971+ }
972+ }
973+
974+ find(byteStringsLast, math.min(end, length), length)
975+ }
976+ }
977+
978+ override def lastIndexOf (elem : Byte , end : Int ): Int = {
979+ if (end < 0 ) - 1
980+ else {
981+ if (end < 0 ) - 1
982+ else {
983+ val byteStringsLast = bytestrings.size - 1
984+
985+ @ tailrec
986+ def find (bsIdx : Int , relativeIndex : Int , len : Int ): Int = {
987+ if (bsIdx < 0 ) - 1
988+ else {
989+ val bs = bytestrings(bsIdx)
990+ val bsStartIndex = len - bs.length
991+
992+ if (relativeIndex < bsStartIndex || bs.isEmpty) {
993+ if (bsIdx == 0 ) - 1
994+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
995+ } else {
996+ val subIndexOf = bs.lastIndexOf(elem, relativeIndex)
997+ if (subIndexOf < 0 ) {
998+ if (bsIdx == 0 ) - 1
999+ else find(bsIdx - 1 , relativeIndex, bsStartIndex)
1000+ } else subIndexOf + bsStartIndex
1001+ }
1002+ }
1003+ }
1004+
1005+ find(byteStringsLast, math.min(end, length), length)
1006+ }
1007+ }
1008+ }
1009+
8981010 override def copyToArray [B >: Byte ](dest : Array [B ], start : Int , len : Int ): Int = {
8991011 if (bytestrings.size == 1 ) bytestrings.head.copyToArray(dest, start, len)
9001012 else {
@@ -1056,6 +1168,31 @@ sealed abstract class ByteString
10561168 */
10571169 def indexOf (elem : Byte ): Int = indexOf(elem, 0 )
10581170
1171+ /**
1172+ * Finds index of last occurrence of some byte in this ByteString before or at some end index.
1173+ *
1174+ * Similar to lastIndexOf, but it avoids boxing if the value is already a byte.
1175+ *
1176+ * @param elem the element value to search for.
1177+ * @param end the end index
1178+ * @return the index `<= end` of the last element of this ByteString that is equal (as determined by `==`)
1179+ * to `elem`, or `-1`, if none exists.
1180+ * @since 2.0.0
1181+ */
1182+ def lastIndexOf (elem : Byte , end : Int ): Int = lastIndexOf[Byte ](elem, end)
1183+
1184+ /**
1185+ * Finds index of last occurrence of some byte in this ByteString.
1186+ *
1187+ * Similar to lastIndexOf, but it avoids boxing if the value is already a byte.
1188+ *
1189+ * @param elem the element value to search for.
1190+ * @return the index of the last element of this ByteString that is equal (as determined by `==`)
1191+ * to `elem`, or `-1`, if none exists.
1192+ * @since 2.0.0
1193+ */
1194+ def lastIndexOf (elem : Byte ): Int = lastIndexOf(elem, length - 1 )
1195+
10591196 override def contains [B >: Byte ](elem : B ): Boolean = indexOf(elem, 0 ) != - 1
10601197
10611198 /**
0 commit comments