Before we dig into your main issue I need to address this:
I had started by loading the file using
Data(contentsOf: url, options: .alwaysMapped)
Relying on memory mapping in library code is tricky because you don’t know the origin of the file. Consider this:
A developer writes a Mac app using your library.
A user runs the app and opens a file on a network volume.
The user’s guinea pig chews through their Ethernet cable.
User does something in the app that tries to access a page in the file that’s not already cached. This triggers a page fault.
The virtual memory (VM) system tries to resolve this by reading the file; that read fails with an error because of the activities of the afore-mentioned guinea pig.
Because the VM system can’t satisfy this page fault its only recourse is to trigger a memory access exception in the app.
IMPORTANT This isn’t a Swift error, and nor it is a Objective-C / C++ language exception. Rather, it’s a machine exception. It’s possible to catch this (via a Mach exception handler or a signal handler) but that’s extremely hard to do correctly.
So, if your library wants to work with arbitrary files you must not rely on memory mapping. This is why we have the .mappedIfSafe option, but that’s not suitable for potentially large files on platforms that don’t support anonymous VM (like iOS and its descendants).
With regards your main issue, you wrote:
I don’t think it’s unreasonable to want to access more than 2 GB of
data on a 32-bit system, is it?
Personally I’d ignore this (well, implement a check in your code that explicitly catches and rejects files larger than 2 GiB when running 32-bit). Most 32-bit platforms will not let you map a file that large:
Non-Apple systems tend to split a process’s 32-bit address space between user and kernel ranges, meaning you don’t have access to the full 4 GiB. In many cases this split is 2/2, so it’s simply impossible to map a file that large. Some use a 3/1 split, so it’s theoretically possible to do this, but you’ll end up hitting a limit somewhere in the 2..<3 GiB range. I don’t think it’s worthwhile writing a whole bunch o’ code for that one extra GiB.
iOS and its descendents limit the amount of VM that a single process can use and that limit is way less than 2 GiB.
macOS is one of the very few 4/4 systems out there, where the user space and kernel have their own completely separate address spaces, each of which can host up to 4 GiB. However, this is irrelevant to you because Swift doesn’t not support 32-bit macOS.
Share and Enjoy
Quinn “The Eskimo!” @ DTS @ Apple