@@ -870,26 +870,26 @@ public static Encoding toEncodingIndex(ThreadContext context, IRubyObject enc) {
870870 }
871871
872872 // encoded_dup
873- public static IRubyObject encodedDup (ThreadContext context , IRubyObject newstr , IRubyObject str , Encoding encindex ) {
874- if (encindex == null ) return str .dup ();
873+ public static RubyString encodedDup (ThreadContext context , RubyString str , Encoding encindex , RubyString newstr ) {
874+ if (encindex == null ) return ( RubyString ) str .dup ();
875875 if (newstr == str ) {
876- newstr = str .dup ();
876+ newstr = ( RubyString ) str .dup ();
877877 } else {
878878 // set to same superclass
879- (( RubyBasicObject ) newstr ) .setMetaClass (str .getMetaClass ());
879+ newstr .setMetaClass (str .getMetaClass ());
880880 }
881- (( RubyString ) newstr ) .modify19 ();
882- return strEncodeAssociate (context , newstr , encindex );
881+ newstr .modify19 ();
882+ return strEncodeAssociate (newstr , encindex );
883883 }
884884
885885 // str_encode_associate
886- public static IRubyObject strEncodeAssociate (ThreadContext context , IRubyObject str , Encoding encidx ) {
886+ public static RubyString strEncodeAssociate (RubyString str , Encoding encidx ) {
887887 encAssociateIndex (str , encidx );
888888
889889 if (encAsciicompat (encidx )) {
890- (( RubyString ) str ) .scanForCodeRange ();
890+ str .scanForCodeRange ();
891891 } else {
892- (( RubyString ) str ) .setCodeRange (StringSupport .CR_VALID );
892+ str .setCodeRange (StringSupport .CR_VALID );
893893 }
894894
895895 return str ;
@@ -911,21 +911,25 @@ public static IRubyObject encAssociateIndex(IRubyObject obj, Encoding encidx) {
911911 }
912912
913913 // str_encode
914- public static IRubyObject strEncode (ThreadContext context , IRubyObject str , IRubyObject ... args ) {
915- IRubyObject [] newstr_p = {str };
914+ public static IRubyObject strEncode (ThreadContext context , RubyString str ) {
915+ return strTranscode (context , str , EncodingUtils ::encodedDup );
916+ }
917+
918+ public static IRubyObject strEncode (ThreadContext context , RubyString str , IRubyObject toEncoding ) {
919+ return strTranscode (context , toEncoding , str , EncodingUtils ::encodedDup );
920+ }
916921
917- Encoding dencindex = strTranscode (context , args , newstr_p );
922+ public static IRubyObject strEncode (ThreadContext context , RubyString str , IRubyObject toEncoding , IRubyObject forcedEncoding ) {
923+ return strTranscode (context , toEncoding , forcedEncoding , str , EncodingUtils ::encodedDup );
924+ }
918925
919- return encodedDup (context , newstr_p [0 ], str , dencindex );
926+ public static IRubyObject strEncode (ThreadContext context , RubyString str , IRubyObject toEncoding , IRubyObject forcedEncoding , IRubyObject opts ) {
927+ return strTranscode (context , toEncoding , forcedEncoding , opts , str , EncodingUtils ::encodedDup );
920928 }
921929
922930 // rb_str_encode
923931 public static IRubyObject rbStrEncode (ThreadContext context , IRubyObject str , IRubyObject to , int ecflags , IRubyObject ecopt ) {
924- IRubyObject [] newstr_p = {str };
925-
926- Encoding dencindex = strTranscode0 (context , 1 , new IRubyObject []{to }, newstr_p , ecflags , ecopt );
927-
928- return encodedDup (context , newstr_p [0 ], str , dencindex );
932+ return strTranscode1 (context , to , (RubyString ) str , ecflags , ecopt , EncodingUtils ::encodedDup );
929933 }
930934
931935 // rb_str_encode
@@ -973,76 +977,107 @@ protected static boolean noDecorators(int ecflags) {
973977 }
974978
975979 // str_transcode
976- public static Encoding strTranscode (ThreadContext context , IRubyObject [] args , IRubyObject [] self_p ) {
977- int ecflags = 0 ;
978- int argc = args .length ;
979- IRubyObject [] ecopts_p = {context .nil };
980980
981- if (args .length >= 1 ) {
982- IRubyObject tmp = TypeConverter .checkHashType (context .runtime , args [args .length - 1 ]);
983- if (!tmp .isNil ()) {
984- argc --;
985- ecflags = econvPrepareOpts (context , tmp , ecopts_p );
986- }
981+ public interface TranscodeResult {
982+ RubyString apply (ThreadContext context , RubyString str , Encoding enc , RubyString newStr );
983+ }
984+
985+ public static IRubyObject strTranscode (ThreadContext context , RubyString str , TranscodeResult result ) {
986+ return strTranscode0 (context , str , 0 , context .nil , result );
987+ }
988+
989+ public static IRubyObject strTranscode (ThreadContext context , IRubyObject toEncoding , RubyString str , TranscodeResult result ) {
990+ return strTranscode1 (context , toEncoding , str , 0 , context .nil , result );
991+ }
992+
993+ public static IRubyObject strTranscode (ThreadContext context , IRubyObject toEncoding , IRubyObject forcedEncoding , RubyString str , TranscodeResult result ) {
994+ return strTranscode2 (context , toEncoding , forcedEncoding , str , 0 , context .nil , result );
995+ }
996+
997+ public static IRubyObject strTranscode (ThreadContext context , IRubyObject toEncoding , IRubyObject forcedEncoding , IRubyObject opts , RubyString str , TranscodeResult result ) {
998+ IRubyObject tmp = TypeConverter .checkHashType (context .runtime , opts );
999+ if (tmp .isNil ()) {
1000+ throw context .runtime .newArgumentError (3 , 0 , 2 );
9871001 }
9881002
989- return strTranscode0 (context , argc , args , self_p , ecflags , ecopts_p [0 ]);
1003+ IRubyObject [] ecopts_p = {context .nil };
1004+ int ecflags = econvPrepareOpts (context , tmp , ecopts_p );
1005+ return strTranscode2 (context , toEncoding , forcedEncoding , str , ecflags , ecopts_p [0 ], result );
9901006 }
9911007
992- // str_transcode0
993- public static Encoding strTranscode0 (ThreadContext context , int argc , IRubyObject [] args , IRubyObject [] self_p , int ecflags , IRubyObject ecopts ) {
994- Ruby runtime = context .runtime ;
1008+ private static IRubyObject strTranscode0 (ThreadContext context , RubyString str , int ecflags , IRubyObject ecopts , TranscodeResult result ) {
1009+ IRubyObject toEncoding = context .runtime .getEncodingService ().getDefaultInternal ();
1010+ if (toEncoding == null || toEncoding .isNil ()) {
1011+ if (ecflags == 0 ) return result .apply (context , str , null , str );
1012+ toEncoding = objEncoding (context , str );
1013+ }
9951014
996- IRubyObject str = self_p [0 ];
997- IRubyObject arg1 , arg2 ;
998- Encoding [] senc_p = {null }, denc_p = {null };
999- byte [][] sname_p = {null }, dname_p = {null };
1000- Encoding dencindex ;
10011015 boolean explicitlyInvalidReplace = true ;
1016+ if ((ecflags & EConvFlags .INVALID_MASK ) == 0 ) {
1017+ explicitlyInvalidReplace = false ;
1018+ }
1019+
1020+ ecflags |= EConvFlags .INVALID_REPLACE | EConvFlags .UNDEF_REPLACE ;
1021+
1022+ return strTranscode (context , toEncoding , context .nil , str , ecflags , ecopts , result , explicitlyInvalidReplace );
1023+ }
10021024
1003- if (argc > 2 ) {
1004- throw context .runtime .newArgumentError (args .length , 2 );
1025+ private static IRubyObject strTranscode1 (ThreadContext context , IRubyObject toEncoding , RubyString str , int ecflags , IRubyObject ecopts , TranscodeResult result ) {
1026+ IRubyObject tmp = TypeConverter .checkHashType (context .runtime , toEncoding );
1027+ if (!tmp .isNil ()) {
1028+ IRubyObject [] ecopts_p = {context .nil };
1029+ ecflags = econvPrepareOpts (context , tmp , ecopts_p );
1030+ return strTranscode0 (context , str , ecflags , ecopts_p [0 ], result );
10051031 }
10061032
1007- if (argc == 0 ) {
1008- arg1 = runtime .getEncodingService ().getDefaultInternal ();
1009- if (arg1 == null || arg1 .isNil ()) {
1010- if (ecflags == 0 ) return null ;
1011- arg1 = objEncoding (context , str );
1012- }
1013- if ((ecflags & EConvFlags .INVALID_MASK ) == 0 ) {
1014- explicitlyInvalidReplace = false ;
1015- }
1016- ecflags |= EConvFlags .INVALID_REPLACE | EConvFlags .UNDEF_REPLACE ;
1017- } else {
1018- arg1 = args [0 ];
1033+ return strTranscode (context , toEncoding , context .nil , str , ecflags , ecopts , result , true );
1034+ }
1035+
1036+ private static IRubyObject strTranscode2 (ThreadContext context , IRubyObject toEncoding , IRubyObject forceEncoding , RubyString str , int ecflags , IRubyObject ecopts , TranscodeResult result ) {
1037+ IRubyObject tmp = TypeConverter .checkHashType (context .runtime , forceEncoding );
1038+ if (!tmp .isNil ()) {
1039+ IRubyObject [] ecopts_p = {context .nil };
1040+ ecflags = econvPrepareOpts (context , tmp , ecopts_p );
1041+ return strTranscode1 (context , toEncoding , str , ecflags , ecopts_p [0 ], result );
10191042 }
10201043
1021- arg2 = argc <= 1 ? context .nil : args [1 ];
1022- dencindex = strTranscodeEncArgs (context , str , arg1 , arg2 , sname_p , senc_p , dname_p , denc_p );
1044+ return strTranscode (context , toEncoding , forceEncoding , str , ecflags , ecopts , result , true );
1045+ }
1046+
1047+ private static RubyString strTranscode (ThreadContext context , IRubyObject toEncoding , IRubyObject forceEncoding , RubyString str , int ecflags , IRubyObject ecopts , TranscodeResult result , boolean explicitlyInvalidReplace ) {
1048+ Ruby runtime = context .runtime ;
1049+
1050+ Encoding [] senc_p = {null }, denc_p = {null };
1051+ byte [][] sname_p = {null }, dname_p = {null };
1052+ Encoding dencindex = strTranscodeEncArgs (context , str , toEncoding , forceEncoding , sname_p , senc_p , dname_p , denc_p );
10231053
1024- IRubyObject dest ;
1054+ RubyString dest ;
10251055
10261056 if (noDecorators (ecflags )) {
1057+ dest = str ;
10271058 if (senc_p [0 ] != null && senc_p [0 ] == denc_p [0 ]) {
10281059 if ((ecflags & EConvFlags .INVALID_MASK ) != 0 && explicitlyInvalidReplace ) {
10291060 IRubyObject rep = context .nil ;
10301061 if (!ecopts .isNil ()) {
1031- rep = ((RubyHash )ecopts ).op_aref (context , runtime .newSymbol ("replace" ));
1062+ rep = ((RubyHash ) ecopts ).op_aref (context , runtime .newSymbol ("replace" ));
10321063 }
1033- dest = ((RubyString )str ).encStrScrub (context , senc_p [0 ], rep , Block .NULL_BLOCK );
1034- if (dest .isNil ()) dest = str ;
1035- self_p [0 ] = dest ;
1036- return dencindex ;
1037- }
1038- return arg2 .isNil () ? null : dencindex ;
1039- } else if (senc_p [0 ] != null && denc_p [0 ] != null && senc_p [0 ].isAsciiCompatible () && denc_p [0 ].isAsciiCompatible ()) {
1040- if (((RubyString )str ).scanForCodeRange () == StringSupport .CR_7BIT ) {
1041- return dencindex ;
1064+ IRubyObject scrubbed = str .encStrScrub (context , senc_p [0 ], rep , Block .NULL_BLOCK );
1065+ if (scrubbed .isNil ()) {
1066+ dest = str ;
1067+ } else {
1068+ dest = (RubyString ) scrubbed ;
1069+ }
1070+ } else if (forceEncoding .isNil ()){
1071+ dencindex = null ;
10421072 }
1043- }
1044- if (encodingEqual (sname_p [0 ], dname_p [0 ])) {
1045- return arg2 .isNil () ? null : dencindex ;
1073+ return result .apply (context , str , dencindex , dest );
1074+ } else if (senc_p [0 ] != null && denc_p [0 ] != null
1075+ && senc_p [0 ].isAsciiCompatible () && denc_p [0 ].isAsciiCompatible ()
1076+ && str .scanForCodeRange () == StringSupport .CR_7BIT ) {
1077+ return result .apply (context , str , dencindex , str );
1078+ } else if (encodingEqual (sname_p [0 ], dname_p [0 ])) {
1079+ if (forceEncoding .isNil ()) dencindex = null ;
1080+ return result .apply (context , str , dencindex , str );
10461081 }
10471082 } else {
10481083 if (encodingEqual (sname_p [0 ], dname_p [0 ])) {
@@ -1051,12 +1086,12 @@ public static Encoding strTranscode0(ThreadContext context, int argc, IRubyObjec
10511086 }
10521087 }
10531088
1054- ByteList sp = (( RubyString ) str ) .getByteList ();
1089+ ByteList sp = str .getByteList ();
10551090 ByteList fromp = sp ;
1056- int slen = (( RubyString ) str ) .size ();
1091+ int slen = str .size ();
10571092 int blen = slen + 30 ;
10581093 dest = RubyString .newStringLight (runtime , blen );
1059- ByteList destp = (( RubyString ) dest ) .getByteList ();
1094+ ByteList destp = dest .getByteList ();
10601095
10611096 byte [] frompBytes = fromp .unsafeBytes ();
10621097 byte [] destpBytes = destp .unsafeBytes ();
@@ -1074,9 +1109,7 @@ public static Encoding strTranscode0(ThreadContext context, int argc, IRubyObjec
10741109 dencindex = defineDummyEncoding (context , dname_p [0 ]);
10751110 }
10761111
1077- self_p [0 ] = dest ;
1078-
1079- return dencindex ;
1112+ return result .apply (context , str , dencindex , dest );
10801113 }
10811114
10821115 // rb_obj_encoding
@@ -2341,4 +2374,64 @@ public static Encoding ioStripBOM(RubyIO io) {
23412374 return ioStripBOM (io .getRuntime ().getCurrentContext (), io );
23422375 }
23432376
2377+ @ Deprecated
2378+ public static Encoding strTranscode0 (ThreadContext context , int argc , IRubyObject [] args , IRubyObject [] self_p , int ecflags , IRubyObject ecopts ) {
2379+ Encoding [] enc_p = {null };
2380+ TranscodeResult result = (ctx , str , enc , newStr ) -> {enc_p [0 ] = enc ; self_p [0 ] = newStr ; return newStr ;};
2381+ switch (argc ) {
2382+ case 0 :
2383+ strTranscode0 (context , (RubyString ) self_p [0 ], ecflags , ecopts , result );
2384+ return enc_p [0 ];
2385+ case 1 :
2386+ strTranscode1 (context , args [0 ], (RubyString ) self_p [0 ], ecflags , ecopts , result );
2387+ return enc_p [0 ];
2388+ case 2 :
2389+ strTranscode2 (context , args [0 ], args [1 ], (RubyString ) self_p [0 ], ecflags , ecopts , result );
2390+ return enc_p [0 ];
2391+ default :
2392+ throw context .runtime .newArgumentError (args .length , 2 );
2393+ }
2394+ }
2395+
2396+ @ Deprecated
2397+ public static Encoding strTranscode (ThreadContext context , IRubyObject [] args , IRubyObject [] self_p ) {
2398+ Encoding [] enc_p = {null };
2399+ TranscodeResult result = (ctx , str , enc , newStr ) -> {enc_p [0 ] = enc ; self_p [0 ] = newStr ; return newStr ;};
2400+
2401+ strTranscode (context , args , (RubyString ) self_p [0 ], result );
2402+
2403+ return enc_p [0 ];
2404+ }
2405+
2406+ @ Deprecated
2407+ public static IRubyObject strEncode (ThreadContext context , IRubyObject str , IRubyObject ... args ) {
2408+ return strTranscode (context , args , (RubyString ) str , EncodingUtils ::encodedDup );
2409+ }
2410+
2411+ @ Deprecated
2412+ public static IRubyObject encodedDup (ThreadContext context , IRubyObject newstr , IRubyObject str , Encoding encindex ) {
2413+ return encodedDup (context , (RubyString ) newstr , encindex , (RubyString ) str );
2414+ }
2415+
2416+ @ Deprecated
2417+ public static IRubyObject strEncodeAssociate (ThreadContext context , IRubyObject str , Encoding encidx ) {
2418+ return strEncodeAssociate ((RubyString ) str , encidx );
2419+ }
2420+
2421+ @ Deprecated
2422+ public static IRubyObject strTranscode (ThreadContext context , IRubyObject [] args , RubyString str , TranscodeResult result ) {
2423+ switch (args .length ) {
2424+ case 0 :
2425+ return strTranscode (context , str , result );
2426+ case 1 :
2427+ return strTranscode (context , args [0 ], str , result );
2428+ case 2 :
2429+ return strTranscode (context , args [0 ], args [1 ], str , result );
2430+ case 3 :
2431+ return strTranscode (context , args [0 ], args [1 ], args [2 ], str , result );
2432+ default :
2433+ throw context .runtime .newArgumentError (args .length , 2 );
2434+ }
2435+ }
2436+
23442437}
0 commit comments