1// Copyright 2014-2021 Ulrich Kunitz. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package lzma
6
7// states defines the overall state count
8const states = 12
9
10// State maintains the full state of the operation encoding or decoding
11// process.
12type state struct {
13	rep         [4]uint32
14	isMatch     [states << maxPosBits]prob
15	isRepG0Long [states << maxPosBits]prob
16	isRep       [states]prob
17	isRepG0     [states]prob
18	isRepG1     [states]prob
19	isRepG2     [states]prob
20	litCodec    literalCodec
21	lenCodec    lengthCodec
22	repLenCodec lengthCodec
23	distCodec   distCodec
24	state       uint32
25	posBitMask  uint32
26	Properties  Properties
27}
28
29// initProbSlice initializes a slice of probabilities.
30func initProbSlice(p []prob) {
31	for i := range p {
32		p[i] = probInit
33	}
34}
35
36// Reset sets all state information to the original values.
37func (s *state) Reset() {
38	p := s.Properties
39	*s = state{
40		Properties: p,
41		// dict:       s.dict,
42		posBitMask: (uint32(1) << uint(p.PB)) - 1,
43	}
44	initProbSlice(s.isMatch[:])
45	initProbSlice(s.isRep[:])
46	initProbSlice(s.isRepG0[:])
47	initProbSlice(s.isRepG1[:])
48	initProbSlice(s.isRepG2[:])
49	initProbSlice(s.isRepG0Long[:])
50	s.litCodec.init(p.LC, p.LP)
51	s.lenCodec.init()
52	s.repLenCodec.init()
53	s.distCodec.init()
54}
55
56// newState creates a new state from the give Properties.
57func newState(p Properties) *state {
58	s := &state{Properties: p}
59	s.Reset()
60	return s
61}
62
63// deepcopy initializes s as a deep copy of the source.
64func (s *state) deepcopy(src *state) {
65	if s == src {
66		return
67	}
68	s.rep = src.rep
69	s.isMatch = src.isMatch
70	s.isRepG0Long = src.isRepG0Long
71	s.isRep = src.isRep
72	s.isRepG0 = src.isRepG0
73	s.isRepG1 = src.isRepG1
74	s.isRepG2 = src.isRepG2
75	s.litCodec.deepcopy(&src.litCodec)
76	s.lenCodec.deepcopy(&src.lenCodec)
77	s.repLenCodec.deepcopy(&src.repLenCodec)
78	s.distCodec.deepcopy(&src.distCodec)
79	s.state = src.state
80	s.posBitMask = src.posBitMask
81	s.Properties = src.Properties
82}
83
84// cloneState creates a new clone of the give state.
85func cloneState(src *state) *state {
86	s := new(state)
87	s.deepcopy(src)
88	return s
89}
90
91// updateStateLiteral updates the state for a literal.
92func (s *state) updateStateLiteral() {
93	switch {
94	case s.state < 4:
95		s.state = 0
96		return
97	case s.state < 10:
98		s.state -= 3
99		return
100	}
101	s.state -= 6
102}
103
104// updateStateMatch updates the state for a match.
105func (s *state) updateStateMatch() {
106	if s.state < 7 {
107		s.state = 7
108	} else {
109		s.state = 10
110	}
111}
112
113// updateStateRep updates the state for a repetition.
114func (s *state) updateStateRep() {
115	if s.state < 7 {
116		s.state = 8
117	} else {
118		s.state = 11
119	}
120}
121
122// updateStateShortRep updates the state for a short repetition.
123func (s *state) updateStateShortRep() {
124	if s.state < 7 {
125		s.state = 9
126	} else {
127		s.state = 11
128	}
129}
130
131// states computes the states of the operation codec.
132func (s *state) states(dictHead int64) (state1, state2, posState uint32) {
133	state1 = s.state
134	posState = uint32(dictHead) & s.posBitMask
135	state2 = (s.state << maxPosBits) | posState
136	return
137}
138
139// litState computes the literal state.
140func (s *state) litState(prev byte, dictHead int64) uint32 {
141	lp, lc := uint(s.Properties.LP), uint(s.Properties.LC)
142	litState := ((uint32(dictHead) & ((1 << lp) - 1)) << lc) |
143		(uint32(prev) >> (8 - lc))
144	return litState
145}
146