mirror of
https://github.com/wassname/segpy.git
synced 2026-06-27 18:25:38 +08:00
Refactors conditional to polymorphism in HeaderPacker. About 5% faster at reading trace headers.
This commit is contained in:
+44
-18
@@ -112,19 +112,28 @@ def compile_struct(header_format_class, start_offset=0, length_in_bytes=None, en
|
||||
return cformat, field_name_allocations
|
||||
|
||||
|
||||
def make_header_packer(header_format_class, endian='>'):
|
||||
cformat, field_name_allocations = compile_struct(
|
||||
header_format_class,
|
||||
header_format_class.START_OFFSET_IN_BYTES,
|
||||
header_format_class.LENGTH_IN_BYTES,
|
||||
endian)
|
||||
structure = Struct(cformat)
|
||||
|
||||
one_to_one = all(len(fields) == 1 for fields in field_name_allocations)
|
||||
|
||||
if one_to_one:
|
||||
return BijectiveHeaderPacker(header_format_class, structure, field_name_allocations)
|
||||
return SurjectiveHeaderPacker(header_format_class, structure, field_name_allocations)
|
||||
|
||||
|
||||
class HeaderPacker:
|
||||
"""Packing and unpacking header instances."""
|
||||
|
||||
def __init__(self, header_format_class, endian='>'):
|
||||
def __init__(self, header_format_class, structure, field_name_allocations):
|
||||
self._header_format_class = header_format_class
|
||||
self._format, self._field_name_allocations = compile_struct(
|
||||
header_format_class,
|
||||
header_format_class.START_OFFSET_IN_BYTES,
|
||||
header_format_class.LENGTH_IN_BYTES,
|
||||
endian)
|
||||
self._struct = Struct(self._format)
|
||||
self._one_to_one = all(len(fields) == 1 for fields in self._field_name_allocations)
|
||||
pass
|
||||
self._structure = structure
|
||||
self._field_name_allocations = field_name_allocations
|
||||
|
||||
@property
|
||||
def header_format_class(self):
|
||||
@@ -140,7 +149,16 @@ class HeaderPacker:
|
||||
header.__class__.__name__
|
||||
))
|
||||
values = [getattr(header, names[0]) for names in self._field_name_allocations]
|
||||
return self._struct.pack(*values)
|
||||
return self._structure.pack(*values)
|
||||
|
||||
def __repr__(self):
|
||||
return "{}({})".format(
|
||||
self.__class__.__name__,
|
||||
self._header_format_class.__name__)
|
||||
|
||||
|
||||
class BijectiveHeaderPacker(HeaderPacker):
|
||||
"""One-to-one packing/unpacking of serialised values to header fields."""
|
||||
|
||||
def unpack(self, buffer):
|
||||
"""Unpack a header into a header object.
|
||||
@@ -151,10 +169,23 @@ class HeaderPacker:
|
||||
Returns:
|
||||
The header object.
|
||||
"""
|
||||
values = self._struct.unpack(buffer)
|
||||
values = self._structure.unpack(buffer)
|
||||
return self._header_format_class(*values)
|
||||
|
||||
if self._one_to_one:
|
||||
return self._header_format_class(*values)
|
||||
|
||||
class SurjectiveHeaderPacker(HeaderPacker):
|
||||
"""One-to-many unpacking of serialised values to header fields."""
|
||||
|
||||
def unpack(self, buffer):
|
||||
"""Unpack a header into a header object.
|
||||
|
||||
Overwrites any existing header field values with new values
|
||||
obtained from the buffer.
|
||||
|
||||
Returns:
|
||||
The header object.
|
||||
"""
|
||||
values = self._structure.unpack(buffer)
|
||||
|
||||
kwargs = {name: value
|
||||
for names, value in zip(self._field_name_allocations, values)
|
||||
@@ -162,11 +193,6 @@ class HeaderPacker:
|
||||
|
||||
return self._header_format_class(**kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return "{}({})".format(
|
||||
self.__class__.__name__,
|
||||
self._header_format_class.__name__)
|
||||
|
||||
|
||||
def main():
|
||||
from segpy.trace_header import TraceHeaderRev0
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
from __future__ import print_function
|
||||
from segpy.encoding import ASCII
|
||||
from segpy.packer import HeaderPacker
|
||||
from segpy.packer import make_header_packer
|
||||
|
||||
from segpy.trace_header import TraceHeaderRev1
|
||||
from segpy.util import file_length, filename_from_handle
|
||||
@@ -175,7 +175,7 @@ class SegYReader(object):
|
||||
self._binary_reel_header = binary_reel_header
|
||||
self._extended_textual_headers = extended_textual_headers
|
||||
|
||||
self._trace_header_packer = HeaderPacker(trace_header_format, endian)
|
||||
self._trace_header_packer = make_header_packer(trace_header_format, endian)
|
||||
|
||||
self._trace_offset_catalog = trace_offset_catalog
|
||||
self._trace_length_catalog = trace_length_catalog
|
||||
|
||||
+4
-4
@@ -15,7 +15,7 @@ from segpy.catalog import CatalogBuilder
|
||||
from segpy.datatypes import SEG_Y_TYPE_TO_CTYPE, size_in_bytes, DATA_SAMPLE_FORMAT_TO_SEG_Y_TYPE, CTYPE_TO_SIZE
|
||||
from segpy.encoding import guess_encoding, is_supported_encoding, UnsupportedEncodingError
|
||||
from segpy.ibm_float import IBMFloat
|
||||
from segpy.packer import HeaderPacker
|
||||
from segpy.packer import make_header_packer
|
||||
from segpy.revisions import canonicalize_revision
|
||||
from segpy.trace_header import TraceHeaderRev1
|
||||
from segpy.util import file_length, batched, pad, complementary_intervals, NATIVE_ENDIANNESS, EMPTY_BYTE_STRING
|
||||
@@ -168,7 +168,7 @@ def read_binary_reel_header(fh, endian='>'):
|
||||
endian: '>' for big-endian data (the standard and default), '<' for
|
||||
little-endian (non-standard)
|
||||
"""
|
||||
header_packer = HeaderPacker(BinaryReelHeader, endian)
|
||||
header_packer = make_header_packer(BinaryReelHeader, endian)
|
||||
fh.seek(TEXTUAL_HEADER_NUM_BYTES) # Consider using from_one_based(BinaryReelHeader.START_OFFSET_IN_BYTES)
|
||||
buffer = fh.read(BinaryReelHeader.LENGTH_IN_BYTES)
|
||||
reel_header = header_packer.unpack(buffer)
|
||||
@@ -336,7 +336,7 @@ def catalog_traces(fh, bps, trace_header_format=TraceHeaderRev1, endian='>', pro
|
||||
if not callable(progress_callback):
|
||||
raise TypeError("catalog_traces(): progress callback must be callable")
|
||||
|
||||
trace_header_packer = HeaderPacker(trace_header_format, endian)
|
||||
trace_header_packer = make_header_packer(trace_header_format, endian)
|
||||
|
||||
length = file_length(fh)
|
||||
|
||||
@@ -637,7 +637,7 @@ def write_binary_reel_header(fh, binary_reel_header, endian='>'):
|
||||
The file pointer for fh will be positioned at the first byte following
|
||||
the binary reel header.
|
||||
"""
|
||||
header_packer = HeaderPacker(BinaryReelHeader, endian) # TODO: Hard wiring
|
||||
header_packer = make_header_packer(BinaryReelHeader, endian) # TODO: Hard wiring
|
||||
buffer = header_packer.pack(binary_reel_header)
|
||||
fh.write(buffer)
|
||||
fh.seek(REEL_HEADER_NUM_BYTES)
|
||||
|
||||
Reference in New Issue
Block a user