0
# Window Access
1
2
Interface classes for accessing memory-mapped file content, providing both low-level cursor control for precise memory region management and high-level buffer interface with automatic windowing and string-like access patterns.
3
4
## Capabilities
5
6
### WindowCursor
7
8
Low-level interface providing precise control over memory region mapping and access. Cursors are created by memory managers and provide direct access to mapped memory buffers.
9
10
```python { .api }
11
class WindowCursor:
12
def use_region(self, offset=0, size=0, flags=0):
13
"""
14
Map a file region into memory for access.
15
16
Parameters:
17
- offset (int): Absolute offset in bytes into the file (default: 0)
18
- size (int): Amount of bytes to map. 0 = map as much as possible
19
- flags (int): Additional flags for os.open (used when opening file handles)
20
21
Returns:
22
WindowCursor: Self (for method chaining)
23
24
Note: The actual mapped size may be smaller than requested if the file
25
ends or if the region was created between existing mapped regions.
26
"""
27
28
def unuse_region(self):
29
"""
30
Release the current memory region and free resources.
31
32
Note: Cursor becomes invalid after calling this method.
33
Resources are automatically freed on cursor destruction.
34
"""
35
36
def buffer(self):
37
"""
38
Get memory buffer for the current mapped region.
39
40
Returns:
41
memoryview: Buffer object providing access to mapped memory
42
43
Raises:
44
AssertionError: If cursor is not valid (no region mapped)
45
46
Note: Buffer should not be cached beyond the cursor's lifetime
47
as it prevents resource cleanup.
48
"""
49
50
def map(self):
51
"""
52
Get the underlying raw memory map.
53
54
Returns:
55
mmap.mmap: Raw memory map object
56
57
Note: Offset and size may differ from use_region() parameters.
58
For StaticWindowMapManager, this maps the entire file.
59
"""
60
61
def is_valid(self):
62
"""
63
Check if cursor has a valid mapped region.
64
65
Returns:
66
bool: True if cursor can be used for memory access
67
"""
68
69
def is_associated(self):
70
"""
71
Check if cursor is associated with a file.
72
73
Returns:
74
bool: True if cursor is bound to a specific file
75
"""
76
77
def ofs_begin(self):
78
"""
79
Get absolute offset to the first byte accessible through this cursor.
80
81
Returns:
82
int: Absolute file offset in bytes
83
84
Note: Only valid when is_valid() returns True
85
"""
86
87
def ofs_end(self):
88
"""
89
Get absolute offset to one byte past the last accessible byte.
90
91
Returns:
92
int: Absolute file offset in bytes
93
"""
94
95
def size(self):
96
"""
97
Get number of bytes accessible through this cursor.
98
99
Returns:
100
int: Size of accessible region in bytes
101
"""
102
103
def region(self):
104
"""
105
Get the underlying MapRegion object.
106
107
Returns:
108
MapRegion | None: Current mapped region, or None if invalid
109
"""
110
111
def includes_ofs(self, ofs):
112
"""
113
Check if absolute offset is accessible through this cursor.
114
115
Parameters:
116
- ofs (int): Absolute file offset to check
117
118
Returns:
119
bool: True if offset is within cursor's current region
120
121
Note: Cursor must be valid for this to work correctly.
122
"""
123
124
def file_size(self):
125
"""
126
Get size of the underlying file.
127
128
Returns:
129
int: Total file size in bytes
130
"""
131
132
def path_or_fd(self):
133
"""
134
Get file path or descriptor used to create this cursor.
135
136
Returns:
137
str | int: File path or file descriptor
138
"""
139
140
def path(self):
141
"""
142
Get file path for this cursor.
143
144
Returns:
145
str: File path
146
147
Raises:
148
ValueError: If cursor was created from a file descriptor
149
"""
150
151
def fd(self):
152
"""
153
Get file descriptor for this cursor.
154
155
Returns:
156
int: File descriptor
157
158
Raises:
159
ValueError: If cursor was created from a file path
160
161
Note: File descriptor may no longer be valid.
162
"""
163
164
def assign(self, rhs):
165
"""
166
Copy data from another cursor into this instance.
167
168
Parameters:
169
- rhs (WindowCursor): Source cursor to copy from
170
171
Note: This creates a real copy with independent resource management.
172
Alternatively, use copy.copy() for the same functionality.
173
"""
174
```
175
176
#### Usage Example
177
178
```python
179
import smmap
180
181
manager = smmap.SlidingWindowMapManager()
182
cursor = manager.make_cursor('/path/to/data.bin')
183
184
# Map first 1MB of file
185
cursor.use_region(offset=0, size=1024*1024)
186
187
if cursor.is_valid():
188
print(f"Mapped region: {cursor.ofs_begin()} to {cursor.ofs_end()}")
189
print(f"Region size: {cursor.size()} bytes")
190
print(f"File size: {cursor.file_size()} bytes")
191
192
# Access mapped memory
193
buffer = cursor.buffer()
194
first_byte = buffer[0]
195
header = buffer[:128]
196
197
# Check if specific offset is accessible
198
if cursor.includes_ofs(512000):
199
middle_data = buffer[512000 - cursor.ofs_begin()]
200
201
# Map a different region
202
cursor.use_region(offset=2*1024*1024, size=512*1024) # Map 512KB at 2MB offset
203
if cursor.is_valid():
204
new_buffer = cursor.buffer()
205
data = new_buffer[:1000]
206
207
# Clean up
208
cursor.unuse_region()
209
210
# Context manager support
211
with cursor:
212
cursor.use_region(offset=1000, size=5000)
213
if cursor.is_valid():
214
data = cursor.buffer()[:]
215
# Automatic cleanup on exit
216
```
217
218
### SlidingWindowMapBuffer
219
220
High-level buffer interface providing string-like access to memory-mapped files with automatic windowing. Handles window management transparently, allowing direct indexing and slicing operations.
221
222
```python { .api }
223
class SlidingWindowMapBuffer:
224
def __init__(self, cursor=None, offset=0, size=sys.maxsize, flags=0):
225
"""
226
Initialize buffer for memory-mapped file access.
227
228
Parameters:
229
- cursor (WindowCursor | None): Associated cursor for file access.
230
If None, must call begin_access() before use.
231
- offset (int): Starting offset in file (default: 0)
232
- size (int): Maximum buffer size. If larger than file, file size is used.
233
- flags (int): Additional flags for os.open operations
234
235
Raises:
236
ValueError: If buffer cannot achieve valid state with given parameters
237
"""
238
239
def begin_access(self, cursor=None, offset=0, size=sys.maxsize, flags=0):
240
"""
241
Initialize buffer for file access.
242
243
Parameters:
244
- cursor (WindowCursor | None): Cursor for file access. If None, uses existing cursor.
245
- offset (int): Starting offset in file
246
- size (int): Maximum buffer size
247
- flags (int): Additional flags for file operations
248
249
Returns:
250
bool: True if buffer is ready for use
251
"""
252
253
def end_access(self):
254
"""
255
Release buffer resources and make buffer unusable.
256
257
Note: Automatically called on destruction. Call manually for
258
earlier resource cleanup in persistent buffer instances.
259
"""
260
261
def cursor(self):
262
"""
263
Get associated cursor providing file access.
264
265
Returns:
266
WindowCursor: Underlying cursor object
267
"""
268
269
def __len__(self):
270
"""
271
Get buffer length.
272
273
Returns:
274
int: Buffer size in bytes
275
"""
276
277
def __getitem__(self, key):
278
"""
279
Get byte(s) at index or slice.
280
281
Parameters:
282
- key (int | slice): Index or slice specification
283
284
Returns:
285
int | bytes: Single byte value or byte sequence
286
287
Note: Automatically maps required windows as needed.
288
Supports negative indexing for end-relative access.
289
"""
290
```
291
292
#### Usage Example
293
294
```python
295
import smmap
296
297
manager = smmap.SlidingWindowMapManager()
298
299
# Direct initialization with cursor
300
cursor = manager.make_cursor('/path/to/large_file.dat')
301
buffer = smmap.SlidingWindowMapBuffer(cursor)
302
303
# String-like access with automatic windowing
304
print(f"File size: {len(buffer)} bytes")
305
306
# Direct byte access
307
first_byte = buffer[0]
308
last_byte = buffer[-1]
309
310
# Slice access
311
header = buffer[:1024] # First 1KB
312
trailer = buffer[-1024:] # Last 1KB
313
middle_chunk = buffer[1000000:1001000] # 1KB at 1MB offset
314
315
# Context manager for automatic cleanup
316
with smmap.SlidingWindowMapBuffer() as buf:
317
# Initialize for specific region
318
if buf.begin_access(cursor, offset=2048, size=1024*1024):
319
# Access relative to buffer start (offset 2048 in file = index 0 in buffer)
320
data = buf[0:100] # First 100 bytes of the buffer region
321
322
# Check buffer state
323
print(f"Buffer covers {len(buf)} bytes")
324
print(f"Cursor valid: {buf.cursor().is_valid()}")
325
326
# Automatic cleanup on context exit
327
328
# Manual resource management
329
buf = smmap.SlidingWindowMapBuffer()
330
try:
331
buf.begin_access(cursor, offset=0)
332
333
# Process file in chunks
334
chunk_size = 64 * 1024
335
for i in range(0, len(buf), chunk_size):
336
chunk = buf[i:i+chunk_size]
337
# Process chunk
338
pass
339
340
finally:
341
buf.end_access()
342
```
343
344
## Access Patterns
345
346
### Sequential Access
347
```python
348
# Efficient sequential reading
349
cursor = manager.make_cursor(file_path)
350
cursor.use_region(offset=0, size=window_size)
351
352
offset = 0
353
while cursor.is_valid():
354
buffer = cursor.buffer()
355
# Process buffer content
356
357
offset += cursor.size()
358
cursor.use_region(offset=offset, size=window_size)
359
```
360
361
### Random Access
362
```python
363
# Random access with buffer interface
364
with smmap.SlidingWindowMapBuffer(manager.make_cursor(file_path)) as buf:
365
# Access any location efficiently
366
header = buf[0:64]
367
footer = buf[-64:]
368
middle = buf[len(buf)//2:len(buf)//2+64]
369
```
370
371
### Multi-cursor Access
372
```python
373
# Multiple cursors for parallel access
374
cursor1 = manager.make_cursor(file_path)
375
cursor2 = manager.make_cursor(file_path)
376
377
# Different regions simultaneously
378
cursor1.use_region(offset=0, size=1024*1024)
379
cursor2.use_region(offset=10*1024*1024, size=1024*1024)
380
381
# Independent access to same file
382
data1 = cursor1.buffer()[:]
383
data2 = cursor2.buffer()[:]
384
```
385
386
## Resource Management
387
388
- **Automatic Cleanup**: Context managers and destructors handle resource cleanup
389
- **Reference Counting**: Regions stay mapped while cursors reference them
390
- **Window Management**: Buffers automatically map/unmap windows as needed
391
- **Memory Limits**: Respects manager-configured memory and handle limits
392
- **Copy Semantics**: Cursors support copying for independent access patterns