Skip to content

Commit

Permalink
Refactor CodecFilter generics
Browse files Browse the repository at this point in the history
  • Loading branch information
sethloco committed Nov 4, 2020
1 parent cf16c5e commit af88b1d
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 166 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 0.9.1

- **(Breaking Change only for Codec Implementors)** Removed class generic type from `CodecFilter` class.
- Created extendable base class for FFI-based codec filters: [NativeCodecFilterBase](lib/src/framework/native/filters.dart).
- Created extendable base class for non-FFI codec filters: [DartCodecFilterBase](lib/src/framework/dart/filters.dart).
- Refactored existing codec filters to subclass `NativeCodecFilterBase` and `DartCodecFilterBase`.
- Fixed some minor issues with the [README](README.md).

## 0.9.0

- Initial development release, created by Seth Berman [Instantiations, Inc](https://www.instantiations.com).
Expand Down
6 changes: 5 additions & 1 deletion DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,8 @@ A [simple example](example/rle_example.dart) was created so implementors could s
#### Filters
The framework offers a `CodecFilter` that handles most of the external concerns of codec implementations.
This class is designed to be subclassed, and subclass implementors will override callback hooks for codec initialization
, processing, flushing, finalizing and closing. All provided codecs build off of the `CodecFilter`.
, processing, flushing, finalizing and closing.

To simplify things even more, we provide two `CodecFilter` subclasses for implementors to extend:
- [DartCodecFilter](lib/src/framework/dart/filters.dart) for non-ffi codec implementations
- [NativeCodecFilter](lib/src/framework/native/filters.dart) for ffi codec implementations
69 changes: 3 additions & 66 deletions example/rle_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'dart:convert';
import 'dart:io';

import 'package:es_compression/framework.dart';
import 'package:es_compression/src/framework/dart/filters.dart';

import 'utils/example_utils.dart';

Expand Down Expand Up @@ -84,26 +85,9 @@ class RunLengthEncoder extends CodecConverter {
}

/// Filter that encodes the incoming bytes using a Dart in-memory buffer.
class RunLengthEncoderFilter
extends CodecFilter<DartHeapPointer, DartCodecBuffer, CodecResult> {
class RunLengthEncoderFilter extends DartCodecFilterBase {
int runLength = 1;

@override
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> newBufferHolder(
int length) {
return DartCodecBufferHolder(length);
}

@override
int doInit(
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> inputBufferHolder,
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> outputBufferHolder,
List<int> bytes,
int start,
int end) {
return 0;
}

@override
CodecResult doProcessing(
DartCodecBuffer inputBuffer, DartCodecBuffer outputBuffer) {
Expand All @@ -126,21 +110,6 @@ class RunLengthEncoderFilter
final written = outputBuffer.writeCount - writePos;
return CodecResult(read, written, adjustBufferCounts: false);
}

@override
int doFlush(DartCodecBuffer outputBuffer) {
return 0;
}

@override
int doFinalize(DartCodecBuffer outputBuffer) {
return 0;
}

@override
void doClose() {
// No action
}
}

/// Custom decoder that provides a [CodecSink] with the algorithm
Expand All @@ -156,27 +125,10 @@ class RunLengthDecoder extends CodecConverter {
enum RleState { expecting_length, expecting_data }

/// Filter that decodes the incoming bytes using a Dart in-memory buffer.
class RunLengthDecoderFilter
extends CodecFilter<DartHeapPointer, DartCodecBuffer, CodecResult> {
class RunLengthDecoderFilter extends DartCodecFilterBase {
RleState _state = RleState.expecting_length;
int runLength = 1;

@override
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> newBufferHolder(
int length) {
return DartCodecBufferHolder(length);
}

@override
int doInit(
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> inputBufferHolder,
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> outputBufferHolder,
List<int> bytes,
int start,
int end) {
return 0;
}

@override
CodecResult doProcessing(
DartCodecBuffer inputBuffer, DartCodecBuffer outputBuffer) {
Expand All @@ -202,19 +154,4 @@ class RunLengthDecoderFilter
final written = outputBuffer.writeCount - writePos;
return CodecResult(read, written, adjustBufferCounts: false);
}

@override
int doFlush(DartCodecBuffer outputBuffer) {
return 0;
}

@override
int doFinalize(DartCodecBuffer outputBuffer) {
return 0;
}

@override
void doClose() {
// No action
}
}
1 change: 1 addition & 0 deletions lib/framework.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ library framework;
export 'src/framework/buffers.dart';
export 'src/framework/converters.dart';
export 'src/framework/dart/buffers.dart';
export 'src/framework/dart/filters.dart';
export 'src/framework/filters.dart';
export 'src/framework/sinks.dart';
26 changes: 12 additions & 14 deletions lib/src/brotli/decoder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import 'dart:convert';
import 'dart:ffi';

import 'package:es_compression/src/framework/native/filters.dart';

import '../framework/buffers.dart';
import '../framework/converters.dart';
import '../framework/filters.dart';
Expand Down Expand Up @@ -56,23 +58,26 @@ class BrotliDecoder extends CodecConverter {
}
}

/// Brotli decoding sink internal implementation.
class _BrotliDecoderSink extends CodecSink {
_BrotliDecoderSink._(
ByteConversionSink sink, bool ringBufferReallocation, bool largeWindow)
: super(sink,
_makeBrotliDecompressFilter(ringBufferReallocation, largeWindow));
}

class _BrotliDecompressFilter extends CodecFilter<Pointer<Uint8>,
NativeCodecBuffer, _BrotliDecodingResult> {
/// Internal filter that decompresses brotli bytes.
class _BrotliDecompressFilter extends NativeCodecFilterBase {
/// Dispatcher to make calls via FFI to brotli shared library
final BrotliDispatcher _dispatcher = BrotliDispatcher();

/// Option holder.
final List<int> parameters = List(5);

/// Native brotli state object
BrotliDecoderState _brotliState;

/// Construct an [_BrotliDecompressFilter] with the supplied options.
_BrotliDecompressFilter(
{bool ringBufferReallocation = true,
bool largeWindow = false,
Expand All @@ -92,12 +97,6 @@ class _BrotliDecompressFilter extends CodecFilter<Pointer<Uint8>,
: BrotliConstants.BROTLI_FALSE;
}

@override
CodecBufferHolder<Pointer<Uint8>, NativeCodecBuffer> newBufferHolder(
int length) {
return NativeCodecBufferHolder(length);
}

/// Return [:true:] if there is more data to process, [:false:] otherwise.
@override
bool hasMoreToProcess() {
Expand Down Expand Up @@ -127,8 +126,12 @@ class _BrotliDecompressFilter extends CodecFilter<Pointer<Uint8>,
return 0;
}

/// Perform decompression.
///
/// Answer an [_BrotliDecodingResult] that store how much was read, written
/// and the next read state.
@override
_BrotliDecodingResult doProcessing(
CodecResult doProcessing(
NativeCodecBuffer inputBuffer, NativeCodecBuffer outputBuffer) {
final result = _dispatcher.callBrotliDecoderDecompressStream(
_brotliState,
Expand All @@ -142,11 +145,6 @@ class _BrotliDecompressFilter extends CodecFilter<Pointer<Uint8>,
return _BrotliDecodingResult(read, written, nextReadState);
}

@override
int doFlush(CodecBuffer outputBuffer) {
return 0;
}

@override
int doFinalize(CodecBuffer outputBuffer) {
if (!_dispatcher.callBrotliDecoderIsFinished(_brotliState)) {
Expand Down
16 changes: 7 additions & 9 deletions lib/src/brotli/encoder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'dart:convert';
import 'dart:ffi';
import 'dart:math';

import 'package:es_compression/src/framework/native/filters.dart';

import '../framework/buffers.dart';
import '../framework/converters.dart';
import '../framework/filters.dart';
Expand Down Expand Up @@ -126,6 +128,7 @@ class BrotliEncoder extends CodecConverter {
}
}

/// Brotli encoding sink internal implementation.
class _BrotliEncoderSink extends CodecSink {
_BrotliEncoderSink._(
ByteConversionSink sink,
Expand Down Expand Up @@ -158,16 +161,17 @@ class _BrotliEncoderSink extends CodecSink {

/// This filter contains the implementation details for the usage of the native
/// brotli API bindings.
class _BrotliCompressFilter extends CodecFilter<Pointer<Uint8>,
NativeCodecBuffer, _BrotliEncodingResult> {
class _BrotliCompressFilter extends NativeCodecFilterBase {
/// Dispatcher to make calls via FFI to brotli shared library
final BrotliDispatcher _dispatcher = BrotliDispatcher();

/// Option holder.
final List<int> parameters = List<int>(10);

/// Native brotli context object
BrotliEncoderState _brotliState;

/// Construct an [_BrotliCompressFilter] with the provided options.
_BrotliCompressFilter(
{int level,
int mode,
Expand Down Expand Up @@ -199,12 +203,6 @@ class _BrotliCompressFilter extends CodecFilter<Pointer<Uint8>,
parameters[BrotliConstants.BROTLI_PARAM_NDIRECT] = directDistanceCodeCount;
}

@override
CodecBufferHolder<Pointer<Uint8>, NativeCodecBuffer> newBufferHolder(
int length) {
return NativeCodecBufferHolder(length);
}

/// Init the filter
///
/// Provide appropriate buffer lengths to codec builders
Expand Down Expand Up @@ -238,7 +236,7 @@ class _BrotliCompressFilter extends CodecFilter<Pointer<Uint8>,
///
/// Return an [_BrotliEncodingResult] which describes the amount read/write
@override
_BrotliEncodingResult doProcessing(
CodecResult doProcessing(
NativeCodecBuffer inputBuffer, NativeCodecBuffer outputBuffer) {
final result = _dispatcher.callBrotliEncoderCompressStream(
_brotliState,
Expand Down
59 changes: 59 additions & 0 deletions lib/src/framework/dart/filters.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import '../buffers.dart';
import '../filters.dart';
import 'buffers.dart';

/// Provides a base-class for codec filters that need to use Dart heap-allocated
/// buffers instead of ffi-based buffers.
abstract class DartCodecFilterBase
extends CodecFilter<DartHeapPointer, DartCodecBuffer> {
/// Constructor which allows the user to set the input/output buffer lengths.
DartCodecFilterBase({int inputBufferLength, int outputBufferLength})
: super(
inputBufferLength: inputBufferLength,
outputBufferLength: outputBufferLength);

/// Return a [DartCodecBufferHolder] with the intended [length].
@override
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> newBufferHolder(
int length) {
return DartCodecBufferHolder(length);
}

/// Init the filter.
///
/// The default behavior is to return 0 for the number of bytes read from
/// the input [bytes].
@override
int doInit(
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> inputBufferHolder,
CodecBufferHolder<DartHeapPointer, DartCodecBuffer> outputBufferHolder,
List<int> bytes,
int start,
int end) {
return 0;
}

/// Flush the internal-algorithm buffered output data.
///
/// The default behavior is to return 0 for the number of bytes flushed to the
/// [outputBuffer].
@override
int doFlush(DartCodecBuffer outputBuffer) {
return 0;
}

/// Perform algorithm-specific finalization.
///
/// The default behavior is to return 0 for the number of bytes written to
/// the [outputBuffer].
@override
int doFinalize(DartCodecBuffer outputBuffer) {
return 0;
}

/// Perform tear-down procedures.
///
/// The default behavior is to take no action.
@override
void doClose() {}
}
12 changes: 3 additions & 9 deletions lib/src/framework/filters.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,8 @@ enum CodecFilterState {
/// algorithms and direct the processing of data.
///
/// Generics:
/// The [CodecFilter] has both the [CodecBuffer] and the [CodecResult] as
/// generic types.
/// [P] defines the type to use for the [CodecBuffer]'s memory pointer.
/// [CB] is the implementation type for an abstract [CodecBuffer] of type [P]
/// [CR] is the implementation type for a [CodecResult]
///
/// A [CodecFilter] contains two buffers.
/// An buffer [_inputBuffer] to incoming bytes to process.
Expand All @@ -47,8 +44,7 @@ enum CodecFilterState {
/// A [CodecFilter] also maintains a [state] which can help
/// implementations know what part of the lifecycle the filter is in
/// (i.e. processing vs closed)
abstract class CodecFilter<P, CB extends CodecBuffer<P>,
CR extends CodecResult> {
abstract class CodecFilter<P, CB extends CodecBuffer<P>> {
/// Buffer holder for the input buffer
CodecBufferHolder<P, CB> _inputBufferHolder;

Expand Down Expand Up @@ -160,7 +156,7 @@ abstract class CodecFilter<P, CB extends CodecBuffer<P>,
/// Perform a coder/decoder routine where the bytes from the incoming buffer
/// are processed by the algorithm and the resulting processed bytes are
/// placed in the output buffer
CR _codeOrDecode() {
CodecResult _codeOrDecode() {
final result =
doProcessing(_checkBuffer(_inputBuffer), _checkBuffer(_outputBuffer));
if (result.adjustBufferCounts) {
Expand Down Expand Up @@ -294,7 +290,7 @@ abstract class CodecFilter<P, CB extends CodecBuffer<P>,
///
/// Return a [CodecResult] describing the number of bytes read/written during
/// the processing routine.
CR doProcessing(CB inputBuffer, CB outputBuffer);
CodecResult doProcessing(CB inputBuffer, CB outputBuffer);

/// Subclass Responsibility: Perform algorithm-specific flush.
///
Expand Down Expand Up @@ -334,8 +330,6 @@ abstract class CodecFilter<P, CB extends CodecBuffer<P>,
}

/// Represents the result of encode/decode routines.
///
/// This is a generic type required by a [CodecFilter].
class CodecResult {
/// Number of bytes read by codec routine
final int readCount;
Expand Down
Loading

0 comments on commit af88b1d

Please sign in to comment.