@@ -444,21 +444,8 @@ extension Base64 {
444
444
445
445
static func decode( string encoded: String , options: Data . Base64DecodingOptions = [ ] ) throws -> Data {
446
446
let decoded = try encoded. utf8. withContiguousStorageIfAvailable { characterPointer -> Data in
447
- guard characterPointer. count > 0 else {
448
- return Data ( )
449
- }
450
-
451
- let outputLength = ( ( characterPointer. count + 3 ) / 4 ) * 3
452
-
453
- return try characterPointer. withMemoryRebound ( to: UInt8 . self) { input -> Data in
454
- let pointer = malloc ( outputLength)
455
- let other = pointer? . bindMemory ( to: UInt8 . self, capacity: outputLength)
456
- let target = UnsafeMutableBufferPointer ( start: other, count: outputLength)
457
- var length = outputLength
458
- try Self . _decodeChromiumIgnoringErrors ( from: input, into: target, length: & length, options: options)
459
-
460
- return Data ( bytesNoCopy: pointer!, count: length, deallocator: . free)
461
- }
447
+ // `withContiguousStorageIfAvailable` sadly does not support typed throws
448
+ try Self . _decodeToData ( from: characterPointer, options: options)
462
449
}
463
450
464
451
if decoded != nil {
@@ -471,23 +458,9 @@ extension Base64 {
471
458
}
472
459
473
460
static func decode( data encoded: Data , options: Data . Base64DecodingOptions = [ ] ) throws -> Data {
474
- let decoded = try encoded. withContiguousStorageIfAvailable { characterPointer -> Data in
461
+ let decoded = try encoded. withContiguousStorageIfAvailable { bufferPointer -> Data in
475
462
// `withContiguousStorageIfAvailable` sadly does not support typed throws
476
- guard characterPointer. count > 0 else {
477
- return Data ( )
478
- }
479
-
480
- let outputLength = ( ( characterPointer. count + 3 ) / 4 ) * 3
481
-
482
- return try characterPointer. withMemoryRebound ( to: UInt8 . self) { input -> Data in
483
- let pointer = malloc ( outputLength)
484
- let other = pointer? . bindMemory ( to: UInt8 . self, capacity: outputLength)
485
- let target = UnsafeMutableBufferPointer ( start: other, count: outputLength)
486
- var length = outputLength
487
- try Self . _decodeChromiumIgnoringErrors ( from: input, into: target, length: & length, options: options)
488
-
489
- return Data ( bytesNoCopy: pointer!, count: length, deallocator: . free)
490
- }
463
+ try Self . _decodeToData ( from: bufferPointer, options: options)
491
464
}
492
465
493
466
if decoded != nil {
@@ -502,23 +475,9 @@ extension Base64 {
502
475
return Data ( )
503
476
}
504
477
505
- let decoded = try bytes. withContiguousStorageIfAvailable { characterPointer -> Data in
478
+ let decoded = try bytes. withContiguousStorageIfAvailable { bufferPointer -> Data in
506
479
// `withContiguousStorageIfAvailable` sadly does not support typed throws
507
- guard characterPointer. count > 0 else {
508
- return Data ( )
509
- }
510
-
511
- let outputLength = ( ( characterPointer. count + 3 ) / 4 ) * 3
512
-
513
- return try characterPointer. withMemoryRebound ( to: UInt8 . self) { input -> Data in
514
- let pointer = malloc ( outputLength)
515
- let other = pointer? . bindMemory ( to: UInt8 . self, capacity: outputLength)
516
- let target = UnsafeMutableBufferPointer ( start: other, count: outputLength)
517
- var length = outputLength
518
- try Self . _decodeChromiumIgnoringErrors ( from: input, into: target, length: & length, options: options)
519
-
520
- return Data ( bytesNoCopy: pointer!, count: length, deallocator: . free)
521
- }
480
+ try Self . _decodeToData ( from: bufferPointer, options: options)
522
481
}
523
482
524
483
if decoded != nil {
@@ -528,11 +487,33 @@ extension Base64 {
528
487
return try self . decode ( bytes: Array ( bytes) , options: options)
529
488
}
530
489
490
+ static func _decodeToData( from inBuffer: UnsafeBufferPointer < UInt8 > , options: Data . Base64DecodingOptions ) throws ( DecodingError) -> Data {
491
+ guard inBuffer. count > 0 else {
492
+ return Data ( )
493
+ }
494
+
495
+ let outputLength = ( ( inBuffer. count + 3 ) / 4 ) * 3
496
+
497
+ let pointer = malloc ( outputLength)
498
+ let other = pointer? . bindMemory ( to: UInt8 . self, capacity: outputLength)
499
+ let target = UnsafeMutableBufferPointer ( start: other, count: outputLength)
500
+ var length = outputLength
501
+ if options. contains ( . ignoreUnknownCharacters) {
502
+ try Self . _decodeChromiumIgnoringErrors ( from: inBuffer, into: target, length: & length, options: options)
503
+ } else {
504
+ // for whatever reason I can see this being 10% faster for larger payloads. Maybe better
505
+ // branch prediction?
506
+ try self . _decodeChromium ( from: inBuffer, into: target, length: & length, options: options)
507
+ }
508
+
509
+ return Data ( bytesNoCopy: pointer!, count: length, deallocator: . free)
510
+ }
511
+
531
512
static func _decodeChromium(
532
513
from inBuffer: UnsafeBufferPointer < UInt8 > ,
533
514
into outBuffer: UnsafeMutableBufferPointer < UInt8 > ,
534
515
length: inout Int ,
535
- options: Data . Base64DecodingOptions = [ ]
516
+ options: Data . Base64DecodingOptions
536
517
) throws ( DecodingError) {
537
518
let remaining = inBuffer. count % 4
538
519
guard remaining == 0 else { throw DecodingError . invalidLength }
0 commit comments