@@ -806,4 +806,192 @@ public PBytes maketrans(@SuppressWarnings("unused") PythonClass cls, Object from
806806 }
807807
808808 }
809+
810+ // bytes.translate(table, delete=b'')
811+ // bytearray.translate(table, delete=b'')
812+ @ Builtin (name = "translate" , minNumOfPositionalArgs = 2 , maxNumOfPositionalArgs = 3 , keywordArguments = {"delete" })
813+ @ GenerateNodeFactory
814+ public abstract static class TranslateNode extends PythonBuiltinNode {
815+
816+ @ Child BytesNodes .ToBytesNode toBytesNode ;
817+
818+ @ CompilationFinal private ConditionProfile isLenTable256Profile ;
819+
820+ private BytesNodes .ToBytesNode getToBytesNode () {
821+ if (toBytesNode == null ) {
822+ CompilerDirectives .transferToInterpreterAndInvalidate ();
823+ toBytesNode = insert (BytesNodes .ToBytesNode .create ());
824+ }
825+ return toBytesNode ;
826+ }
827+
828+ private void checkLengthOfTable (byte [] table ) {
829+ if (isLenTable256Profile == null ) {
830+ CompilerDirectives .transferToInterpreterAndInvalidate ();
831+ isLenTable256Profile = ConditionProfile .createBinaryProfile ();
832+ }
833+
834+ if (isLenTable256Profile .profile (table .length != 256 )) {
835+ throw raise (PythonErrorType .ValueError , "translation table must be 256 characters long" );
836+ }
837+ }
838+
839+ private static class Result {
840+ byte [] array ;
841+ // we have to know, whether the result array was changed ->
842+ // if not in bytes case it has to return the input bytes
843+ // in bytearray case it has to return always new bytearray
844+ boolean changed ;
845+
846+ public Result (byte [] array , boolean changed ) {
847+ this .array = array ;
848+ this .changed = changed ;
849+ }
850+ }
851+
852+ private static boolean [] createDeleteTable (byte [] delete ) {
853+ boolean [] result = new boolean [256 ];
854+ for (int i = 0 ; i < 256 ; i ++) {
855+ result [i ] = false ;
856+ }
857+ for (int i = 0 ; i < delete .length ; i ++) {
858+ result [delete [i ]] = true ;
859+ }
860+ return result ;
861+ }
862+
863+ private static Result delete (byte [] self , byte [] table ) {
864+ final int length = self .length ;
865+ byte [] result = new byte [length ];
866+ int resultLen = 0 ;
867+ boolean [] toDelete = createDeleteTable (table );
868+
869+ for (int i = 0 ; i < length ; i ++) {
870+ if (!toDelete [self [i ] & 0xFF ]) {
871+ result [resultLen ] = self [i ];
872+ resultLen ++;
873+ }
874+ }
875+ if (resultLen == length ) {
876+ return new Result (result , false );
877+ }
878+ return new Result (Arrays .copyOf (result , resultLen ), true );
879+ }
880+
881+ private static Result translate (byte [] self , byte [] table ) {
882+ final int length = self .length ;
883+ byte [] result = new byte [length ];
884+ boolean changed = false ;
885+ for (int i = 0 ; i < length ; i ++) {
886+ byte b = table [self [i ]];
887+ if (!changed && b != self [i ]) {
888+ changed = true ;
889+ }
890+ result [i ] = b ;
891+ }
892+ return new Result (result , changed );
893+ }
894+
895+ private static Result translateAndDelete (byte [] self , byte [] table , byte [] delete ) {
896+ final int length = self .length ;
897+ byte [] result = new byte [length ];
898+ int resultLen = 0 ;
899+ boolean changed = false ;
900+ boolean [] toDelete = createDeleteTable (delete );
901+
902+ for (int i = 0 ; i < length ; i ++) {
903+ if (!toDelete [self [i ]]) {
904+ byte b = table [self [i ]];
905+ if (!changed && b != self [i ]) {
906+ changed = true ;
907+ }
908+ result [resultLen ] = b ;
909+ resultLen ++;
910+ }
911+ }
912+ if (resultLen == length ) {
913+ return new Result (result , changed );
914+ }
915+ return new Result (Arrays .copyOf (result , resultLen ), true );
916+ }
917+
918+ @ Specialization (guards = "isNoValue(delete)" )
919+ public PBytes translate (PBytes self , @ SuppressWarnings ("unused" ) PNone table , @ SuppressWarnings ("unused" ) PNone delete ) {
920+ return self ;
921+ }
922+
923+ @ Specialization (guards = "isNoValue(delete)" )
924+ public PByteArray translate (PByteArray self , @ SuppressWarnings ("unused" ) PNone table , @ SuppressWarnings ("unused" ) PNone delete ) {
925+ return factory ().createByteArray (self .getSequenceStorage ().copy ());
926+ }
927+
928+ @ Specialization
929+ public PBytes translate (PBytes self , Object table , @ SuppressWarnings ("unused" ) PNone delete ) {
930+ byte [] bTable = getToBytesNode ().execute (table );
931+ checkLengthOfTable (bTable );
932+ byte [] bSelf = getToBytesNode ().execute (self );
933+
934+ Result result = translate (bSelf , bTable );
935+ if (result .changed ) {
936+ return factory ().createBytes (result .array );
937+ }
938+ return self ;
939+ }
940+
941+ @ Specialization
942+ public PByteArray translate (PByteArray self , Object table , @ SuppressWarnings ("unused" ) PNone delete ) {
943+ byte [] bTable = getToBytesNode ().execute (table );
944+ checkLengthOfTable (bTable );
945+ byte [] bSelf = getToBytesNode ().execute (self );
946+
947+ Result result = translate (bSelf , bTable );
948+ return factory ().createByteArray (result .array );
949+ }
950+
951+ @ Specialization (guards = "isNone(table)" )
952+ public PBytes delete (PBytes self , @ SuppressWarnings ("unused" ) PNone table , Object delete ) {
953+ byte [] bSelf = getToBytesNode ().execute (self );
954+ byte [] bDelete = getToBytesNode ().execute (delete );
955+
956+ Result result = delete (bSelf , bDelete );
957+ if (result .changed ) {
958+ return factory ().createBytes (result .array );
959+ }
960+ return self ;
961+ }
962+
963+ @ Specialization (guards = "isNone(table)" )
964+ public PByteArray delete (PByteArray self , @ SuppressWarnings ("unused" ) PNone table , Object delete ) {
965+ byte [] bSelf = getToBytesNode ().execute (self );
966+ byte [] bDelete = getToBytesNode ().execute (delete );
967+
968+ Result result = delete (bSelf , bDelete );
969+ return factory ().createByteArray (result .array );
970+ }
971+
972+ @ Specialization (guards = {"!isPNone(table)" , "!isPNone(delete)" })
973+ public PBytes translateAndDelete (PBytes self , Object table , Object delete ) {
974+ byte [] bTable = getToBytesNode ().execute (table );
975+ checkLengthOfTable (bTable );
976+ byte [] bDelete = getToBytesNode ().execute (delete );
977+ byte [] bSelf = getToBytesNode ().execute (self );
978+
979+ Result result = translateAndDelete (bSelf , bTable , bDelete );
980+ if (result .changed ) {
981+ return factory ().createBytes (result .array );
982+ }
983+ return self ;
984+ }
985+
986+ @ Specialization (guards = {"!isPNone(table)" , "!isPNone(delete)" })
987+ public PByteArray translateAndDelete (PByteArray self , Object table , Object delete ) {
988+ byte [] bTable = getToBytesNode ().execute (table );
989+ checkLengthOfTable (bTable );
990+ byte [] bDelete = getToBytesNode ().execute (delete );
991+ byte [] bSelf = getToBytesNode ().execute (self );
992+
993+ Result result = translateAndDelete (bSelf , bTable , bDelete );
994+ return factory ().createByteArray (result .array );
995+ }
996+ }
809997}
0 commit comments