|
@@ -5,204 +5,170 @@ import (
|
|
|
"fmt"
|
|
"fmt"
|
|
|
"log"
|
|
"log"
|
|
|
"math"
|
|
"math"
|
|
|
- "os"
|
|
|
|
|
"time"
|
|
"time"
|
|
|
|
|
|
|
|
- "p78git.ddns.net/svi/packer/internal/packer/dict_keys"
|
|
|
|
|
- "p78git.ddns.net/svi/packer/internal/packer/freq_pair"
|
|
|
|
|
- "p78git.ddns.net/svi/packer/internal/packer/frequencer"
|
|
|
|
|
- "p78git.ddns.net/svi/packer/pkg/types"
|
|
|
|
|
|
|
+ . "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
|
|
|
|
|
+
|
|
|
|
|
+ "gitp78su.ipnodns.ru/svi/packer/internal/belt"
|
|
|
|
|
+ "gitp78su.ipnodns.ru/svi/packer/internal/packer/dict_keys"
|
|
|
|
|
+ "gitp78su.ipnodns.ru/svi/packer/internal/packer/freq_pair"
|
|
|
|
|
+ "gitp78su.ipnodns.ru/svi/packer/internal/packer/frequencer"
|
|
|
|
|
+ "gitp78su.ipnodns.ru/svi/packer/pkg/types"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
-// Packer -- упаковщик сервиса
|
|
|
|
|
-type Packer struct {
|
|
|
|
|
- serv types.IService
|
|
|
|
|
- dictKeys types.IDictKeys // Словарь ключей
|
|
|
|
|
- freqPair *freq_pair.FreqPair // Частотная пара
|
|
|
|
|
- frequencer types.IFrequencer // Подбор частотной пары
|
|
|
|
|
- binData []uint16 // То, что останется после замен
|
|
|
|
|
- timeTotal float32 // Общее время в сек
|
|
|
|
|
- totalChange int // Общее число замен
|
|
|
|
|
- originSize int // Оригинальный размер
|
|
|
|
|
- binNew []uint16 // Буфер новых данных
|
|
|
|
|
|
|
+// Пакер -- упаковщик сервиса
|
|
|
|
|
+type Пакер struct {
|
|
|
|
|
+ словКлючи *dict_keys.СловКлючи // Словарь ключей
|
|
|
|
|
+ частотПара *freq_pair.ЧастотПара // Частотная пара
|
|
|
|
|
+ частотник types.ИЧастотник // Подбор частотной пары
|
|
|
|
|
+ времВсего float32 // Общее время в сек
|
|
|
|
|
+ заменВсего int // Общее число замен
|
|
|
|
|
+ лента *belt.Лента
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// NewPacker -- возвращает ноый пакер
|
|
|
|
|
-func NewPacker(serv types.IService) (*Packer, error) {
|
|
|
|
|
- if serv == nil {
|
|
|
|
|
- return nil, fmt.Errorf("NewPacker(): IService==nil")
|
|
|
|
|
- }
|
|
|
|
|
- sf := &Packer{
|
|
|
|
|
- serv: serv,
|
|
|
|
|
- dictKeys: dict_keys.NewDictKeys(),
|
|
|
|
|
- freqPair: &freq_pair.FreqPair{},
|
|
|
|
|
- binData: []uint16{},
|
|
|
|
|
- binNew: []uint16{0, 0, 0},
|
|
|
|
|
- }
|
|
|
|
|
- var err error
|
|
|
|
|
- sf.frequencer, err = frequencer.NewFrequencer(sf)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return nil, fmt.Errorf("NewPacker(): in create IFrequencer, err=\n\t%w", err)
|
|
|
|
|
|
|
+// НовПакер -- возвращает новый пакер
|
|
|
|
|
+func НовПакер() *Пакер {
|
|
|
|
|
+ сам := &Пакер{
|
|
|
|
|
+ словКлючи: dict_keys.СловКлючиПолуч(),
|
|
|
|
|
+ частотПара: &freq_pair.ЧастотПара{},
|
|
|
|
|
+ лента: belt.ЛентаПолуч(),
|
|
|
|
|
+ частотник: frequencer.НовЧастотник(),
|
|
|
}
|
|
}
|
|
|
- _ = types.IPacker(sf)
|
|
|
|
|
- return sf, nil
|
|
|
|
|
|
|
+ return сам
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Run -- запускает упаковку
|
|
|
|
|
-func (sf *Packer) Run() error {
|
|
|
|
|
- log.Printf("Packer.Run()\n")
|
|
|
|
|
- { // Чтение файла
|
|
|
|
|
- fileName := os.Getenv("PACK_FILE")
|
|
|
|
|
- if fileName == "" {
|
|
|
|
|
- return fmt.Errorf("Packer.Run(): env PACK_FILE not set")
|
|
|
|
|
- }
|
|
|
|
|
- binData, err := os.ReadFile(fileName)
|
|
|
|
|
- if err != nil {
|
|
|
|
|
- return fmt.Errorf("Packer.Run(): in read %q, err=\n\t%w", fileName, err)
|
|
|
|
|
- }
|
|
|
|
|
- sf.originSize = len(binData)
|
|
|
|
|
- for _, val := range binData {
|
|
|
|
|
- sf.binData = append(sf.binData, uint16(val))
|
|
|
|
|
- }
|
|
|
|
|
- log.Printf("Packer.Run(): len(%q)=%v\n", fileName, len(sf.binData))
|
|
|
|
|
- }
|
|
|
|
|
- round := 1
|
|
|
|
|
|
|
+// Пуск -- запускает упаковку
|
|
|
|
|
+func (сам *Пакер) Пуск() error {
|
|
|
|
|
+ log.Printf("Пакер.Пуск()\n")
|
|
|
|
|
+ сам.словКлючи.ПервичЗаполн(сам.лента.Исх())
|
|
|
|
|
+ раундСчёт := 1
|
|
|
for { // Главный цикл сжатия
|
|
for { // Главный цикл сжатия
|
|
|
- log.Printf("Packer.Run(): round=%v, lenDict=%v\n", round, sf.dictKeys.Len())
|
|
|
|
|
- if !sf.round() {
|
|
|
|
|
|
|
+ if !сам.раунд() {
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
- round++
|
|
|
|
|
|
|
+ log.Printf("Пакер.Пуск(): раунд=%v, ключиВсего=%v\n\n", раундСчёт, сам.словКлючи.Всего())
|
|
|
|
|
+ раундСчёт++
|
|
|
}
|
|
}
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Serv -- возвращает сервис
|
|
|
|
|
-func (sf *Packer) Serv() types.IService {
|
|
|
|
|
- return sf.serv
|
|
|
|
|
|
|
+// СловКлючи -- возвращает словарь ключей для подстановки
|
|
|
|
|
+func (sf *Пакер) СловКлючи() types.ИСловКлючи {
|
|
|
|
|
+ return sf.словКлючи
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// BinData -- возвращает бинарны данные для упаковки
|
|
|
|
|
-func (sf *Packer) BinData() []uint16 {
|
|
|
|
|
- return sf.binData
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// DictKeys -- возвращает словарь ключей для подстановки
|
|
|
|
|
-func (sf *Packer) DictKeys() types.IDictKeys {
|
|
|
|
|
- return sf.dictKeys
|
|
|
|
|
|
|
+func (сам *Пакер) времРаунд(времНач int64) {
|
|
|
|
|
+ времКонец := time.Now().Local().UnixMilli()
|
|
|
|
|
+ времРаунд := float32(времКонец-времНач) / 1000
|
|
|
|
|
+ сам.времВсего += времРаунд
|
|
|
|
|
+ словБит := 8
|
|
|
|
|
+ ключейВсего := сам.словКлючи.Всего()
|
|
|
|
|
+ switch {
|
|
|
|
|
+ case 256 <= ключейВсего && ключейВсего < 512:
|
|
|
|
|
+ словБит = 9
|
|
|
|
|
+ case 512 <= ключейВсего && ключейВсего < 1024:
|
|
|
|
|
+ словБит = 10
|
|
|
|
|
+ case 1024 <= ключейВсего && ключейВсего < 2048:
|
|
|
|
|
+ словБит = 11
|
|
|
|
|
+ case 2048 <= ключейВсего && ключейВсего < 4096:
|
|
|
|
|
+ словБит = 12
|
|
|
|
|
+ case 4096 <= ключейВсего && ключейВсего < 8191:
|
|
|
|
|
+ словБит = 13
|
|
|
|
|
+ case 8192 <= ключейВсего && ключейВсего < 16383:
|
|
|
|
|
+ словБит = 14
|
|
|
|
|
+ case ключейВсего >= 16384:
|
|
|
|
|
+ Hassert(false, "Пакер.времРаунд(): слишком много ключей(%v)", ключейВсего)
|
|
|
|
|
+ }
|
|
|
|
|
+ размерНов := int((float32(len(сам.лента.Вых()) + ключейВсего)) * (float32(словБит) / 8))
|
|
|
|
|
+ сжатие := float32(размерНов) / float32(сам.лента.ИсхРазмер()) * 100
|
|
|
|
|
+ log.Printf("Пакер.времРаунд(): время(всего=%0.2fsec, раунд=%0.2fsec), сжатие=%0.2f%%, заменВсего=%v\n",
|
|
|
|
|
+ сам.времВсего,
|
|
|
|
|
+ времРаунд,
|
|
|
|
|
+ сжатие,
|
|
|
|
|
+ сам.заменВсего)
|
|
|
|
|
+ log.Printf("Пакер.времРаунд(): размерИсх=%v размерНов=%v\n", сам.лента.ИсхРазмер(), размерНов)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Выполняет раунд сжатия
|
|
// Выполняет раунд сжатия
|
|
|
-func (sf *Packer) round() bool {
|
|
|
|
|
- timeBeg := time.Now().Local().UnixMilli()
|
|
|
|
|
- defer func() {
|
|
|
|
|
- timeEnd := time.Now().Local().UnixMilli()
|
|
|
|
|
- timeDelta := float32(timeEnd-timeBeg) / 1000
|
|
|
|
|
- sf.timeTotal += timeDelta
|
|
|
|
|
- binOrigin := sf.originSize * 8
|
|
|
|
|
- multFactor := 8
|
|
|
|
|
- lenDict := sf.dictKeys.Len()
|
|
|
|
|
- switch {
|
|
|
|
|
- case lenDict < 256:
|
|
|
|
|
- multFactor = 8
|
|
|
|
|
- case 256 <= lenDict && lenDict < 512:
|
|
|
|
|
- multFactor = 9
|
|
|
|
|
- case 512 <= lenDict && lenDict < 1024:
|
|
|
|
|
- multFactor = 10
|
|
|
|
|
- case 1024 <= lenDict && lenDict < 2048:
|
|
|
|
|
- multFactor = 11
|
|
|
|
|
- case 2048 <= lenDict && lenDict < 4096:
|
|
|
|
|
- multFactor = 12
|
|
|
|
|
- case 4096 <= lenDict && lenDict < 8200:
|
|
|
|
|
- multFactor = 13
|
|
|
|
|
- default:
|
|
|
|
|
- multFactor = 14
|
|
|
|
|
- }
|
|
|
|
|
- binPack := len(sf.binData)*multFactor + lenDict*3*multFactor
|
|
|
|
|
- ratio := (1 - float32(binOrigin)/float32(binPack)) * 100
|
|
|
|
|
- log.Printf("Packer.Round(): timeTotal=%0.2fsec, timeRound=%0.2fsec, ration=%0.2f%%, totalChange=%v\n\n",
|
|
|
|
|
- sf.timeTotal,
|
|
|
|
|
- timeDelta,
|
|
|
|
|
- ratio,
|
|
|
|
|
- sf.totalChange)
|
|
|
|
|
- }()
|
|
|
|
|
- sf.dictUp()
|
|
|
|
|
- if err := sf.frequencer.Run(); err != nil {
|
|
|
|
|
- log.Printf("Packer.round(): in work IFrequencer, err=\n\t%v\n", err)
|
|
|
|
|
|
|
+func (сам *Пакер) раунд() bool {
|
|
|
|
|
+ времНач := time.Now().Local().UnixMilli()
|
|
|
|
|
+ defer сам.времРаунд(времНач)
|
|
|
|
|
+ // сам.словУст()
|
|
|
|
|
+ if err := сам.частотник.Пуск(); err != nil {
|
|
|
|
|
+ log.Printf("Пакер.round(): in work IFrequencer, err=\n\t%v\n", err)
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
- sf.freqPair.SetKeys(sf.frequencer.Keys())
|
|
|
|
|
- keyNext, err := sf.keyNext()
|
|
|
|
|
|
|
+ сам.частотПара.SetKeys(сам.частотник.Ключи())
|
|
|
|
|
+ keyNext, err := сам.keyNext()
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
- log.Printf("Packer.round(): limit keys, err=\n\t%v\n", err)
|
|
|
|
|
|
|
+ log.Printf("Пакер.раунд(): limit keys, err=\n\t%v\n", err)
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
- sf.changeKey(keyNext)
|
|
|
|
|
|
|
+ сам.сменитьКлюч(keyNext)
|
|
|
return true
|
|
return true
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Заменяет частотную пару на указанный ключ
|
|
// Заменяет частотную пару на указанный ключ
|
|
|
-func (sf *Packer) changeKey(key uint16) {
|
|
|
|
|
- sf.binNew = sf.binNew[:0]
|
|
|
|
|
- val0 := sf.binData[0]
|
|
|
|
|
|
|
+func (сам *Пакер) сменитьКлюч(key uint32) {
|
|
|
|
|
+ binNew := сам.лента.Вых()
|
|
|
|
|
+ исхРазмер := len(binNew)
|
|
|
|
|
+ binNew = binNew[:0]
|
|
|
|
|
+ val0 := binNew[0]
|
|
|
ind := 1
|
|
ind := 1
|
|
|
- val1 := sf.binData[ind]
|
|
|
|
|
|
|
+ val1 := binNew[ind]
|
|
|
fnNext := func() bool { // вычисляет сдвиг после замены
|
|
fnNext := func() bool { // вычисляет сдвиг после замены
|
|
|
- sf.binNew = append(sf.binNew, key)
|
|
|
|
|
- if ind+1 >= len(sf.binData) { // Достигнут предел прохода
|
|
|
|
|
|
|
+ binNew = append(binNew, key)
|
|
|
|
|
+ if ind+1 >= len(binNew) { // Достигнут предел прохода
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
ind++
|
|
ind++
|
|
|
- val0 = sf.binData[ind]
|
|
|
|
|
- if ind+1 >= len(sf.binData) { // Достигнут предел прохода
|
|
|
|
|
|
|
+ val0 = binNew[ind]
|
|
|
|
|
+ if ind+1 >= len(binNew) { // Достигнут предел прохода
|
|
|
return false
|
|
return false
|
|
|
}
|
|
}
|
|
|
ind++
|
|
ind++
|
|
|
- val1 = sf.binData[ind]
|
|
|
|
|
|
|
+ val1 = binNew[ind]
|
|
|
return true
|
|
return true
|
|
|
}
|
|
}
|
|
|
- key0 := sf.freqPair.Key0_
|
|
|
|
|
- key1 := sf.freqPair.Key1_
|
|
|
|
|
- for ind < len(sf.binData) {
|
|
|
|
|
- val1 = sf.binData[ind]
|
|
|
|
|
|
|
+ key0 := сам.частотПара.Key0_
|
|
|
|
|
+ key1 := сам.частотПара.Key1_
|
|
|
|
|
+ for ind < len(binNew) {
|
|
|
|
|
+ val1 = binNew[ind]
|
|
|
if val0 == key0 && val1 == key1 {
|
|
if val0 == key0 && val1 == key1 {
|
|
|
fnNext()
|
|
fnNext()
|
|
|
continue
|
|
continue
|
|
|
}
|
|
}
|
|
|
- sf.binNew = append(sf.binNew, val0)
|
|
|
|
|
|
|
+ binNew = append(binNew, val0)
|
|
|
val0 = val1
|
|
val0 = val1
|
|
|
ind++
|
|
ind++
|
|
|
}
|
|
}
|
|
|
- countChange := len(sf.binData) - len(sf.binNew)
|
|
|
|
|
- sf.totalChange += countChange
|
|
|
|
|
- log.Printf("Packer.changeKey(): len{old=%v, new=%v}, numChange=%v\n",
|
|
|
|
|
- len(sf.binData),
|
|
|
|
|
- len(sf.binNew),
|
|
|
|
|
- countChange)
|
|
|
|
|
- sf.binData = sf.binNew
|
|
|
|
|
|
|
+ countChange := исхРазмер - len(binNew)
|
|
|
|
|
+ сам.заменВсего += countChange
|
|
|
|
|
+ log.Printf("Пакер.сменитьКлюч(): раундЗамены=%v\n", countChange)
|
|
|
|
|
+ сам.лента.ВыхУст(binNew)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Ищёт следующий свободный ключ
|
|
|
|
|
-func (sf *Packer) keyNext() (uint16, error) {
|
|
|
|
|
- key := uint16(0)
|
|
|
|
|
|
|
+// Ищет следующий свободный ключ
|
|
|
|
|
+func (sf *Пакер) keyNext() (uint32, error) {
|
|
|
|
|
+ key := uint32(0)
|
|
|
for {
|
|
for {
|
|
|
- if !sf.dictKeys.IsExists(key) {
|
|
|
|
|
|
|
+ if !sf.словКлючи.ЕслиЕсть(key) {
|
|
|
return key, nil
|
|
return key, nil
|
|
|
}
|
|
}
|
|
|
key++
|
|
key++
|
|
|
if key == math.MaxUint16 {
|
|
if key == math.MaxUint16 {
|
|
|
- return 0, fmt.Errorf("Packer.keyNext(): key up to limit uint32")
|
|
|
|
|
|
|
+ return 0, fmt.Errorf("Пакер.keyNext(): key up to limit uint32")
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Собирает словарь ключей из текста
|
|
// Собирает словарь ключей из текста
|
|
|
-func (sf *Packer) dictUp() {
|
|
|
|
|
- // Собрать встречающиеся ключи
|
|
|
|
|
- for _, val := range sf.binData {
|
|
|
|
|
- if !sf.dictKeys.IsExists(val) {
|
|
|
|
|
- sf.dictKeys.Add(val)
|
|
|
|
|
- continue
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+// func (sf *Пакер) словУст() {
|
|
|
|
|
+// // Собрать встречающиеся ключи
|
|
|
|
|
+// for _, знач := range sf.бинТекст {
|
|
|
|
|
+// if !sf.словКлючи.ЕслиЕсть(знач) {
|
|
|
|
|
+// sf.словКлючи.Доб(знач)
|
|
|
|
|
+// continue
|
|
|
|
|
+// }
|
|
|
|
|
+// }
|
|
|
|
|
+// }
|