Diff

Differences From Artifact [f2ad12a795]:

To Artifact [cebf1719c8]:


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

40
41
42
43
44

45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

61
62
63
64
65
66
67
68

69
70
71
72
73
74
75
76
77
78
79
80




























81
82













83

84
85
86
87
88
89
90
91
92
93
94
95

96

97
98
99
100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
25
26
27
28
29
30
31








32





33











34
35
36
37

38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107
108
109
110
111
112
113

114







115



116













117
118
119







-
-
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-




-
+







-
+










-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+


+
+
+
+
+
+
+
+
+
+
+
+
+
-
+












+
-
+
-
-
-
-
-
-
-

-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-



	240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255,
}

type context struct {
	table [256]byte
}

// Returns an MTF encoder over the provided io.Writer
func Encoder(writer io.Writer) io.Writer {
	var enc encoder
	enc.table = initial
	enc.target = writer
	return &enc
}

// Encodes data in place
type encoder struct {
	context
	target io.Writer
}

func (c *context) encode(data []byte) {
func (c *encoder) Write(data []byte) (int, error) {
	var (
		dataLength int    = len(data)
		buffer     []byte = make([]byte, dataLength)
	)

	// io.Write must not modify the passed data in any way
	// TODO - check sync.Pool or a local free-list for amortizing buffers
	// TODO - use a buffer with a fixed max size to avoid OOM conditions

	// Loop over the input data
	for index, value := range data {

		// Shortcut for sequential, equal values
		if c.table[0] == value {
			buffer[index] = 0
			data[index] = 0
			continue
		}

		// Loop over the MTF table
		for j := byte(1); j != 0; j++ {
			if c.table[j] == value {
				// Output the value
				buffer[index] = j
				data[index] = j

				// Shift the table
				copy(c.table[1:], c.table[:j])

				// Restore the value in front and break
				c.table[0] = value
				break
			}
		}
	}

	return c.target.Write(buffer)
}

// Decode data in place
func (c *context) decode(data []byte) {
	for index, value := range data {
		position := value

		// Shortcut for sequential, equal values
		if position == 0 {
			data[index] = c.table[0]
			continue
		}

		// Output the value
		data[index] = c.table[position]

		// Shift the table and restore the value in front
		copy(c.table[1:], c.table[:position])
		c.table[0] = data[index]
	}
}

// Returns an MTF encoder over the provided io.Reader
func Encoder(reader io.Reader) io.Reader {
	var enc encoder
	enc.table = initial
	enc.source = reader
	return &enc
}

type encoder struct {
	context
	source io.Reader
}

// Read and encode data in place
func (c *encoder) Read(output []byte) (count int, err error) {
	count, err = c.source.Read(output)
	c.encode(output[:count])

	return count, err
}

// Returns an MTF decoder over the provided io.Writer
// Returns an MTF decoder over the provided io.Reader
func Decoder(reader io.Reader) io.Reader {
	var dec decoder
	dec.table = initial
	dec.source = reader
	return &dec
}

type decoder struct {
	context
	source io.Reader
}

// Read and decode data in place
func (c *decoder) Read(output []byte) (int, error) {
func (c *decoder) Read(output []byte) (count int, err error) {
	var (
		count    int
		err      error
		position byte
	)

	// Read from the source and decode in place
	count, err = c.source.Read(output)
	for i := 0; i < count; i++ {
		position = output[i]

	c.decode(output[:count])
		// Shortcut for sequential, equal values
		if position == 0 {
			output[i] = c.table[0]
			continue
		}

		// Output the value
		output[i] = c.table[position]

		// Shift the table and restore the value in front
		copy(c.table[1:], c.table[:position])
		c.table[0] = output[i]
	}

	return count, err
}