@aguacerowx/react-native 0.0.38 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -204,34 +204,86 @@ public class GridRenderLayer: NSObject {
204
204
 
205
205
  private func reconstructAndTransformInPlace(data: inout Data) {
206
206
  let count = data.count
207
- if count == 0 { return }
207
+ guard count > 0 else { return }
208
208
 
209
- // Get raw pointer to memory (Bypasses Swift Array bounds checking)
210
209
  data.withUnsafeMutableBytes { rawBuffer in
211
- guard let ptr = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return }
212
-
213
- // 1. Setup first byte
214
- // Cast to Int8 to handle the delta logic, then back to UInt8 for storage
215
- var runningValue: Int8 = Int8(bitPattern: ptr[0])
216
-
217
- // Transform first byte immediately: runningValue + 128
218
- // We use &+ to allow overflow wrapping (which is exactly what we want for -128->0 mapping)
219
- ptr[0] = UInt8(bitPattern: runningValue) &+ 128
210
+ guard let baseAddress = rawBuffer.baseAddress else { return }
211
+ let int8Ptr = baseAddress.assumingMemoryBound(to: Int8.self)
212
+ let uint8Ptr = baseAddress.assumingMemoryBound(to: UInt8.self)
213
+
214
+ // --- PHASE 1: Parallel local prefix sums ---
215
+ // Each thread independently prefix-sums its own chunk.
216
+ // At the end of this phase, each chunk is correct RELATIVE to its own start,
217
+ // but incorrect in absolute terms (missing the sum of all prior chunks).
218
+
219
+ let threadCount = min(ProcessInfo.processInfo.activeProcessorCount, 8)
220
+ let chunkSize = (count + threadCount - 1) / threadCount
221
+
222
+ // Stores the final value of each chunk after its local prefix sum.
223
+ // This is the "carry" we need to propagate forward.
224
+ var chunkEndValues = [Int8](repeating: 0, count: threadCount)
225
+
226
+ DispatchQueue.concurrentPerform(iterations: threadCount) { t in
227
+ let start = t * chunkSize
228
+ let end = min(start + chunkSize, count)
229
+ guard start < end else { return }
230
+
231
+ // Local prefix sum within this chunk only
232
+ for i in (start + 1)..<end {
233
+ int8Ptr[i] = int8Ptr[i] &+ int8Ptr[i - 1]
234
+ }
235
+ chunkEndValues[t] = int8Ptr[end - 1]
236
+ }
220
237
 
221
- // 2. Optimized Loop (One pass for everything)
222
- for i in 1..<count {
223
- let delta = Int8(bitPattern: ptr[i])
224
-
225
- // Reconstruction: Add delta to previous value
226
- runningValue = runningValue &+ delta
227
-
228
- // Transformation: Add 128 to shift into UInt8 range for Texture
229
- ptr[i] = UInt8(bitPattern: runningValue) &+ 128
238
+ // --- PHASE 2: Sequential fixup of chunk offsets ---
239
+ // Compute the running offset that needs to be added to each chunk.
240
+ // This must be sequential since each offset depends on the previous.
241
+ var offsets = [Int8](repeating: 0, count: threadCount)
242
+ // Chunk 0 needs no offset (it's already correct from index 0)
243
+ for t in 1..<threadCount {
244
+ offsets[t] = offsets[t - 1] &+ chunkEndValues[t - 1]
245
+ }
246
+
247
+ // --- PHASE 3: Parallel offset application + XOR transform ---
248
+ // Apply the offset correction AND the +128 transform in one pass.
249
+ // XOR with 0x80 is equivalent to adding 128 mod 256.
250
+
251
+ DispatchQueue.concurrentPerform(iterations: threadCount) { t in
252
+ let start = t * chunkSize
253
+ let end = min(start + chunkSize, count)
254
+ guard start < end else { return }
255
+
256
+ let offset = offsets[t]
257
+
258
+ if offset == 0 {
259
+ // Chunk 0: no offset needed, just XOR transform
260
+ // Process 8 bytes at a time using UInt64
261
+ let wordStart = start
262
+ let wordCount = (end - start) / 8
263
+ let uint64Ptr = baseAddress.assumingMemoryBound(to: UInt64.self)
264
+ let wordOffset = wordStart / 8
265
+
266
+ for i in 0..<wordCount {
267
+ uint64Ptr[wordOffset + i] ^= 0x8080808080808080
268
+ }
269
+ // Remaining bytes
270
+ for i in (wordStart + wordCount * 8)..<end {
271
+ uint8Ptr[i] ^= 0x80
272
+ }
273
+ } else {
274
+ // Chunks 1+: add offset correction, then XOR transform
275
+ // Note: we have to do byte-by-byte here because the offset
276
+ // applies additively in Int8 space before the UInt8 XOR
277
+ for i in start..<end {
278
+ let corrected = int8Ptr[i] &+ offset
279
+ uint8Ptr[i] = UInt8(bitPattern: corrected) ^ 0x80
280
+ }
281
+ }
230
282
  }
231
283
  }
232
284
  }
233
285
 
234
- private func processRawData(fileData: Data) -> Data? {
286
+ private func processRawData(fileData: Data) -> Data? {
235
287
  let start = CFAbsoluteTimeGetCurrent()
236
288
 
237
289
  // 1. Decompress
@@ -204,34 +204,86 @@ public class GridRenderLayer: NSObject {
204
204
 
205
205
  private func reconstructAndTransformInPlace(data: inout Data) {
206
206
  let count = data.count
207
- if count == 0 { return }
207
+ guard count > 0 else { return }
208
208
 
209
- // Get raw pointer to memory (Bypasses Swift Array bounds checking)
210
209
  data.withUnsafeMutableBytes { rawBuffer in
211
- guard let ptr = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return }
212
-
213
- // 1. Setup first byte
214
- // Cast to Int8 to handle the delta logic, then back to UInt8 for storage
215
- var runningValue: Int8 = Int8(bitPattern: ptr[0])
216
-
217
- // Transform first byte immediately: runningValue + 128
218
- // We use &+ to allow overflow wrapping (which is exactly what we want for -128->0 mapping)
219
- ptr[0] = UInt8(bitPattern: runningValue) &+ 128
210
+ guard let baseAddress = rawBuffer.baseAddress else { return }
211
+ let int8Ptr = baseAddress.assumingMemoryBound(to: Int8.self)
212
+ let uint8Ptr = baseAddress.assumingMemoryBound(to: UInt8.self)
213
+
214
+ // --- PHASE 1: Parallel local prefix sums ---
215
+ // Each thread independently prefix-sums its own chunk.
216
+ // At the end of this phase, each chunk is correct RELATIVE to its own start,
217
+ // but incorrect in absolute terms (missing the sum of all prior chunks).
218
+
219
+ let threadCount = min(ProcessInfo.processInfo.activeProcessorCount, 8)
220
+ let chunkSize = (count + threadCount - 1) / threadCount
221
+
222
+ // Stores the final value of each chunk after its local prefix sum.
223
+ // This is the "carry" we need to propagate forward.
224
+ var chunkEndValues = [Int8](repeating: 0, count: threadCount)
225
+
226
+ DispatchQueue.concurrentPerform(iterations: threadCount) { t in
227
+ let start = t * chunkSize
228
+ let end = min(start + chunkSize, count)
229
+ guard start < end else { return }
230
+
231
+ // Local prefix sum within this chunk only
232
+ for i in (start + 1)..<end {
233
+ int8Ptr[i] = int8Ptr[i] &+ int8Ptr[i - 1]
234
+ }
235
+ chunkEndValues[t] = int8Ptr[end - 1]
236
+ }
220
237
 
221
- // 2. Optimized Loop (One pass for everything)
222
- for i in 1..<count {
223
- let delta = Int8(bitPattern: ptr[i])
224
-
225
- // Reconstruction: Add delta to previous value
226
- runningValue = runningValue &+ delta
227
-
228
- // Transformation: Add 128 to shift into UInt8 range for Texture
229
- ptr[i] = UInt8(bitPattern: runningValue) &+ 128
238
+ // --- PHASE 2: Sequential fixup of chunk offsets ---
239
+ // Compute the running offset that needs to be added to each chunk.
240
+ // This must be sequential since each offset depends on the previous.
241
+ var offsets = [Int8](repeating: 0, count: threadCount)
242
+ // Chunk 0 needs no offset (it's already correct from index 0)
243
+ for t in 1..<threadCount {
244
+ offsets[t] = offsets[t - 1] &+ chunkEndValues[t - 1]
245
+ }
246
+
247
+ // --- PHASE 3: Parallel offset application + XOR transform ---
248
+ // Apply the offset correction AND the +128 transform in one pass.
249
+ // XOR with 0x80 is equivalent to adding 128 mod 256.
250
+
251
+ DispatchQueue.concurrentPerform(iterations: threadCount) { t in
252
+ let start = t * chunkSize
253
+ let end = min(start + chunkSize, count)
254
+ guard start < end else { return }
255
+
256
+ let offset = offsets[t]
257
+
258
+ if offset == 0 {
259
+ // Chunk 0: no offset needed, just XOR transform
260
+ // Process 8 bytes at a time using UInt64
261
+ let wordStart = start
262
+ let wordCount = (end - start) / 8
263
+ let uint64Ptr = baseAddress.assumingMemoryBound(to: UInt64.self)
264
+ let wordOffset = wordStart / 8
265
+
266
+ for i in 0..<wordCount {
267
+ uint64Ptr[wordOffset + i] ^= 0x8080808080808080
268
+ }
269
+ // Remaining bytes
270
+ for i in (wordStart + wordCount * 8)..<end {
271
+ uint8Ptr[i] ^= 0x80
272
+ }
273
+ } else {
274
+ // Chunks 1+: add offset correction, then XOR transform
275
+ // Note: we have to do byte-by-byte here because the offset
276
+ // applies additively in Int8 space before the UInt8 XOR
277
+ for i in start..<end {
278
+ let corrected = int8Ptr[i] &+ offset
279
+ uint8Ptr[i] = UInt8(bitPattern: corrected) ^ 0x80
280
+ }
281
+ }
230
282
  }
231
283
  }
232
284
  }
233
285
 
234
- private func processRawData(fileData: Data) -> Data? {
286
+ private func processRawData(fileData: Data) -> Data? {
235
287
  let start = CFAbsoluteTimeGetCurrent()
236
288
 
237
289
  // 1. Decompress
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aguacerowx/react-native",
3
- "version": "0.0.38",
3
+ "version": "0.0.41",
4
4
  "description": "Native weather rendering for React Native",
5
5
  "license": "ISC",
6
6
  "author": "Michael Barletta",
@@ -204,34 +204,86 @@ public class GridRenderLayer: NSObject {
204
204
 
205
205
  private func reconstructAndTransformInPlace(data: inout Data) {
206
206
  let count = data.count
207
- if count == 0 { return }
207
+ guard count > 0 else { return }
208
208
 
209
- // Get raw pointer to memory (Bypasses Swift Array bounds checking)
210
209
  data.withUnsafeMutableBytes { rawBuffer in
211
- guard let ptr = rawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { return }
212
-
213
- // 1. Setup first byte
214
- // Cast to Int8 to handle the delta logic, then back to UInt8 for storage
215
- var runningValue: Int8 = Int8(bitPattern: ptr[0])
216
-
217
- // Transform first byte immediately: runningValue + 128
218
- // We use &+ to allow overflow wrapping (which is exactly what we want for -128->0 mapping)
219
- ptr[0] = UInt8(bitPattern: runningValue) &+ 128
210
+ guard let baseAddress = rawBuffer.baseAddress else { return }
211
+ let int8Ptr = baseAddress.assumingMemoryBound(to: Int8.self)
212
+ let uint8Ptr = baseAddress.assumingMemoryBound(to: UInt8.self)
213
+
214
+ // --- PHASE 1: Parallel local prefix sums ---
215
+ // Each thread independently prefix-sums its own chunk.
216
+ // At the end of this phase, each chunk is correct RELATIVE to its own start,
217
+ // but incorrect in absolute terms (missing the sum of all prior chunks).
218
+
219
+ let threadCount = min(ProcessInfo.processInfo.activeProcessorCount, 8)
220
+ let chunkSize = (count + threadCount - 1) / threadCount
221
+
222
+ // Stores the final value of each chunk after its local prefix sum.
223
+ // This is the "carry" we need to propagate forward.
224
+ var chunkEndValues = [Int8](repeating: 0, count: threadCount)
225
+
226
+ DispatchQueue.concurrentPerform(iterations: threadCount) { t in
227
+ let start = t * chunkSize
228
+ let end = min(start + chunkSize, count)
229
+ guard start < end else { return }
230
+
231
+ // Local prefix sum within this chunk only
232
+ for i in (start + 1)..<end {
233
+ int8Ptr[i] = int8Ptr[i] &+ int8Ptr[i - 1]
234
+ }
235
+ chunkEndValues[t] = int8Ptr[end - 1]
236
+ }
220
237
 
221
- // 2. Optimized Loop (One pass for everything)
222
- for i in 1..<count {
223
- let delta = Int8(bitPattern: ptr[i])
224
-
225
- // Reconstruction: Add delta to previous value
226
- runningValue = runningValue &+ delta
227
-
228
- // Transformation: Add 128 to shift into UInt8 range for Texture
229
- ptr[i] = UInt8(bitPattern: runningValue) &+ 128
238
+ // --- PHASE 2: Sequential fixup of chunk offsets ---
239
+ // Compute the running offset that needs to be added to each chunk.
240
+ // This must be sequential since each offset depends on the previous.
241
+ var offsets = [Int8](repeating: 0, count: threadCount)
242
+ // Chunk 0 needs no offset (it's already correct from index 0)
243
+ for t in 1..<threadCount {
244
+ offsets[t] = offsets[t - 1] &+ chunkEndValues[t - 1]
245
+ }
246
+
247
+ // --- PHASE 3: Parallel offset application + XOR transform ---
248
+ // Apply the offset correction AND the +128 transform in one pass.
249
+ // XOR with 0x80 is equivalent to adding 128 mod 256.
250
+
251
+ DispatchQueue.concurrentPerform(iterations: threadCount) { t in
252
+ let start = t * chunkSize
253
+ let end = min(start + chunkSize, count)
254
+ guard start < end else { return }
255
+
256
+ let offset = offsets[t]
257
+
258
+ if offset == 0 {
259
+ // Chunk 0: no offset needed, just XOR transform
260
+ // Process 8 bytes at a time using UInt64
261
+ let wordStart = start
262
+ let wordCount = (end - start) / 8
263
+ let uint64Ptr = baseAddress.assumingMemoryBound(to: UInt64.self)
264
+ let wordOffset = wordStart / 8
265
+
266
+ for i in 0..<wordCount {
267
+ uint64Ptr[wordOffset + i] ^= 0x8080808080808080
268
+ }
269
+ // Remaining bytes
270
+ for i in (wordStart + wordCount * 8)..<end {
271
+ uint8Ptr[i] ^= 0x80
272
+ }
273
+ } else {
274
+ // Chunks 1+: add offset correction, then XOR transform
275
+ // Note: we have to do byte-by-byte here because the offset
276
+ // applies additively in Int8 space before the UInt8 XOR
277
+ for i in start..<end {
278
+ let corrected = int8Ptr[i] &+ offset
279
+ uint8Ptr[i] = UInt8(bitPattern: corrected) ^ 0x80
280
+ }
281
+ }
230
282
  }
231
283
  }
232
284
  }
233
285
 
234
- private func processRawData(fileData: Data) -> Data? {
286
+ private func processRawData(fileData: Data) -> Data? {
235
287
  let start = CFAbsoluteTimeGetCurrent()
236
288
 
237
289
  // 1. Decompress
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aguacerowx/react-native",
3
- "version": "0.0.38",
3
+ "version": "0.0.41",
4
4
  "description": "Native weather rendering for React Native",
5
5
  "license": "ISC",
6
6
  "author": "Michael Barletta",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aguacerowx/react-native",
3
- "version": "0.0.38",
3
+ "version": "0.0.41",
4
4
  "description": "Native weather rendering for React Native",
5
5
  "license": "ISC",
6
6
  "author": "Michael Barletta",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aguacerowx/react-native",
3
- "version": "0.0.38",
3
+ "version": "0.0.41",
4
4
  "description": "Native weather rendering for React Native",
5
5
  "license": "ISC",
6
6
  "author": "Michael Barletta",
@@ -1,19 +0,0 @@
1
- #import <React/RCTBridgeModule.h>
2
- #import <React/RCTViewManager.h>
3
-
4
- // This file acts as a central manifest for all your native code.
5
- // The autolinker will find this and use it to register your modules.
6
-
7
- // --- Make sure these module names match your Swift/Objective-C class names ---
8
-
9
- // Exposing the Swift module to Objective-C
10
- @interface RCT_EXTERN_MODULE(WeatherFrameProcessorModule, NSObject)
11
- @end
12
-
13
- // Exposing the Swift module to Objective-C
14
- @interface RCT_EXTERN_MODULE(InspectorModule, NSObject)
15
- @end
16
-
17
- // Exposing the ViewManager to Objective-C
18
- @interface RCT_EXTERN_MODULE(GridRenderLayerManager, RCTViewManager)
19
- @end
@@ -1,16 +0,0 @@
1
- import Foundation
2
- import simd
3
-
4
- // Must match the fragment shader's uniform structure
5
- struct FragmentUniforms {
6
- var opacity: Float
7
- var dataRange: SIMD2<Float>
8
- var scale: Float
9
- var offset: Float
10
- var missingQuantized: Float
11
- var textureSize: SIMD2<Float>
12
- var smoothing: Int32
13
- var scaleType: Int32
14
- var isPtype: Int32
15
- var isMRMS: Int32
16
- }