Skip to content

Commit c19837a

Browse files
committed
Оптимизировано потребление памяти за счет интернирования объектов и строк
1 parent b8e6f88 commit c19837a

File tree

162 files changed

+8654
-8114
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

162 files changed

+8654
-8114
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ dependencies {
5555

5656
// прочее
5757
implementation("commons-io", "commons-io", "2.8.0")
58-
implementation("com.github.1c-syntax", "utils", "0.5.1")
58+
implementation("io.github.1c-syntax", "utils", "0.6.0")
5959
implementation("io.github.1c-syntax", "bsl-common-library", "0.5.1")
6060
implementation("io.github.1c-syntax", "supportconf", "0.14.0") {
6161
exclude("io.github.1c-syntax", "bsl-common-library")

src/main/java/com/github/_1c_syntax/bsl/mdo/Language.java

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
1-
/*
2-
* This file is a part of MDClasses.
3-
*
4-
* Copyright (c) 2019 - 2024
5-
* Tymko Oleg <olegtymko@yandex.ru>, Maximov Valery <maximovvalery@gmail.com> and contributors
6-
*
7-
* SPDX-License-Identifier: LGPL-3.0-or-later
8-
*
9-
* MDClasses is free software; you can redistribute it and/or
10-
* modify it under the terms of the GNU Lesser General Public
11-
* License as published by the Free Software Foundation; either
12-
* version 3.0 of the License, or (at your option) any later version.
13-
*
14-
* MDClasses is distributed in the hope that it will be useful,
15-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17-
* Lesser General Public License for more details.
18-
*
19-
* You should have received a copy of the GNU Lesser General Public
20-
* License along with MDClasses.
21-
*/
22-
package com.github._1c_syntax.bsl.mdo;
1+
/*
2+
* This file is a part of MDClasses.
3+
*
4+
* Copyright (c) 2019 - 2024
5+
* Tymko Oleg <olegtymko@yandex.ru>, Maximov Valery <maximovvalery@gmail.com> and contributors
6+
*
7+
* SPDX-License-Identifier: LGPL-3.0-or-later
8+
*
9+
* MDClasses is free software; you can redistribute it and/or
10+
* modify it under the terms of the GNU Lesser General Public
11+
* License as published by the Free Software Foundation; either
12+
* version 3.0 of the License, or (at your option) any later version.
13+
*
14+
* MDClasses is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
* Lesser General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with MDClasses.
21+
*/
22+
package com.github._1c_syntax.bsl.mdo;
2323

2424
import com.github._1c_syntax.bsl.mdo.support.MultiLanguageString;
2525
import com.github._1c_syntax.bsl.mdo.support.ObjectBelonging;
@@ -33,8 +33,6 @@
3333
import lombok.ToString;
3434
import lombok.Value;
3535

36-
import java.util.Map;
37-
3836
/**
3937
* ВНИМАНИЕ!
4038
* Для формата EDT хранится в файле Configuration.mdo, т.е. отдельного файла нет
@@ -101,7 +99,7 @@ private static Language newLanguage(String name, String code) {
10199
return Language.builder()
102100
.name(name)
103101
.uuid("")
104-
.synonym(new MultiLanguageString(Map.of(code, name)))
102+
.synonym(MultiLanguageString.create(code, name))
105103
.mdoReference(MdoReference.create(
106104
MDOType.LANGUAGE,
107105
MDOType.LANGUAGE.getGroupName() + "." + name,

src/main/java/com/github/_1c_syntax/bsl/mdo/storage/form/FormHandler.java

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,61 @@
2121
*/
2222
package com.github._1c_syntax.bsl.mdo.storage.form;
2323

24+
import com.github._1c_syntax.utils.GenericInterner;
25+
import com.github._1c_syntax.utils.StringInterner;
26+
import edu.umd.cs.findbugs.annotations.Nullable;
27+
import lombok.EqualsAndHashCode;
28+
import lombok.Value;
29+
import lombok.experimental.Accessors;
30+
2431
/**
2532
* Обработчик события формы
26-
*
27-
* @param event Имя события
28-
* @param name Имя обработчика (метода) формы
2933
*/
30-
public record FormHandler(String event, String name) {
34+
@Value
35+
@EqualsAndHashCode
36+
public class FormHandler implements Comparable<FormHandler> {
37+
38+
private static final GenericInterner<FormHandler> interner = new GenericInterner<>();
39+
private static final StringInterner stringInterner = new StringInterner();
40+
41+
@Accessors(fluent = true)
42+
String event;
43+
@Accessors(fluent = true)
44+
String name;
45+
46+
private FormHandler(String event, String name) {
47+
this.event = stringInterner.intern(event);
48+
this.name = stringInterner.intern(name);
49+
}
50+
51+
/**
52+
* @param event Имя события
53+
* @param name Имя обработчика (метода) формы
54+
*/
55+
56+
public static FormHandler create(String event, String name) {
57+
return new FormHandler(event, name).intern();
58+
}
59+
60+
@Override
61+
public int compareTo(@Nullable FormHandler formHandler) {
62+
if (formHandler == null) {
63+
return 1;
64+
}
65+
66+
if (this.equals(formHandler)) {
67+
return 0;
68+
}
69+
70+
int compareResult = event.compareTo(formHandler.event);
71+
if (compareResult != 0) {
72+
return compareResult;
73+
}
74+
75+
return name.compareTo(formHandler.name);
76+
}
77+
78+
private FormHandler intern() {
79+
return interner.intern(this);
80+
}
3181
}

src/main/java/com/github/_1c_syntax/bsl/mdo/support/MultiLanguageString.java

Lines changed: 126 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,44 +21,57 @@
2121
*/
2222
package com.github._1c_syntax.bsl.mdo.support;
2323

24+
import com.github._1c_syntax.utils.GenericInterner;
2425
import com.github._1c_syntax.utils.StringInterner;
26+
import edu.umd.cs.findbugs.annotations.Nullable;
27+
import lombok.EqualsAndHashCode;
28+
import lombok.Getter;
2529
import lombok.NonNull;
2630
import lombok.Value;
2731

2832
import java.util.Collections;
29-
import java.util.HashMap;
33+
import java.util.HashSet;
3034
import java.util.List;
3135
import java.util.Map;
36+
import java.util.Set;
3237

3338
/**
3439
* Используется для хранения текстовой строки на разных языках
3540
*/
3641
@Value
37-
public class MultiLanguageString {
42+
@EqualsAndHashCode
43+
public class MultiLanguageString implements Comparable<MultiLanguageString> {
3844

3945
/**
4046
* Ссылка на пустой элемент
4147
*/
4248
public static final MultiLanguageString EMPTY = new MultiLanguageString(Collections.emptyMap());
43-
44-
private static final StringInterner stringInterner = new StringInterner();
49+
private static final GenericInterner<MultiLanguageString> interner = new GenericInterner<>();
4550

4651
/**
4752
* Содержимое описания для каждого языка
4853
*/
49-
Map<String, String> content;
54+
Set<Entry> content;
5055

51-
public MultiLanguageString(Map<String, String> source) {
52-
Map<String, String> newContent = new HashMap<>();
56+
private MultiLanguageString(@NonNull Map<String, String> source) {
57+
Set<Entry> newContent = new HashSet<>();
5358
source.forEach(
54-
(langKey, text) -> newContent.put(stringInterner.intern(langKey), text));
55-
content = newContent;
59+
(langKey, text) -> newContent.add(Entry.create(langKey, text)));
60+
content = Collections.unmodifiableSet(newContent);
61+
}
62+
63+
private MultiLanguageString(@NonNull String langKey, @NonNull String value) {
64+
this(Set.of(Entry.create(langKey, value)));
65+
}
66+
67+
private MultiLanguageString(@NonNull MultiLanguageString first, @NonNull MultiLanguageString second) {
68+
var fullContent = new HashSet<>(first.getContent());
69+
fullContent.addAll(second.getContent());
70+
content = Collections.unmodifiableSet(fullContent);
5671
}
5772

58-
public MultiLanguageString(@NonNull MultiLanguageString first, @NonNull MultiLanguageString second) {
59-
var fullContent = new HashMap<>(first.getContent());
60-
putContent(fullContent, second);
61-
content = fullContent;
73+
private MultiLanguageString(Set<Entry> content) {
74+
this.content = Collections.unmodifiableSet(content);
6275
}
6376

6477
/**
@@ -69,26 +82,42 @@ public MultiLanguageString(@NonNull MultiLanguageString first, @NonNull MultiLan
6982
* @param strings Список мультиязычных строк
7083
* @return Объединенное значение
7184
*/
72-
public static MultiLanguageString of(@NonNull List<MultiLanguageString> strings) {
85+
public static MultiLanguageString create(@NonNull List<MultiLanguageString> strings) {
7386
if (strings.isEmpty()) {
7487
return EMPTY;
7588
} else if (strings.size() == 1) {
7689
return strings.get(0);
7790
} else {
78-
Map<String, String> content = new HashMap<>();
79-
strings.forEach(string -> putContent(content, string));
80-
return new MultiLanguageString(content);
91+
Set<Entry> content = new HashSet<>();
92+
strings.forEach(string -> content.addAll(string.getContent()));
93+
return new MultiLanguageString(content).intern();
8194
}
8295
}
8396

97+
public static MultiLanguageString create(@NonNull Set<Entry> langContent) {
98+
return new MultiLanguageString(langContent).intern();
99+
}
100+
101+
public static MultiLanguageString create(@NonNull MultiLanguageString first, @NonNull MultiLanguageString second) {
102+
return new MultiLanguageString(first, second).intern();
103+
}
104+
105+
public static MultiLanguageString create(@NonNull String langKey, @NonNull String value) {
106+
return new MultiLanguageString(langKey, value).intern();
107+
}
108+
84109
/**
85110
* Возвращает содержимое для указанного языка
86111
*
87112
* @param lang Требуемый язык
88113
* @return Содержимое для указанного языка
89114
*/
90115
public @NonNull String get(@NonNull String lang) {
91-
return content.getOrDefault(lang, "");
116+
return content.stream()
117+
.filter(entry -> entry.getLangKey().equals(lang))
118+
.map(Entry::getValue)
119+
.findFirst()
120+
.orElse("");
92121
}
93122

94123
/**
@@ -100,7 +129,7 @@ public static MultiLanguageString of(@NonNull List<MultiLanguageString> strings)
100129
if (content.isEmpty()) {
101130
return "";
102131
}
103-
return content.entrySet().iterator().next().getValue();
132+
return content.iterator().next().getValue();
104133
}
105134

106135
/**
@@ -112,8 +141,83 @@ public boolean isEmpty() {
112141
return this == EMPTY;
113142
}
114143

115-
private static void putContent(Map<String, String> destination, MultiLanguageString source) {
116-
source.getContent().forEach(
117-
(langKey, text) -> destination.put(stringInterner.intern(langKey), text));
144+
@Override
145+
public int compareTo(@Nullable MultiLanguageString multiLanguageString) {
146+
if (multiLanguageString == null) {
147+
return 1;
148+
}
149+
150+
if (this.equals(multiLanguageString)) {
151+
return 0;
152+
}
153+
154+
int compareResult = content.size() - multiLanguageString.content.size();
155+
if (compareResult != 0) {
156+
return compareResult;
157+
}
158+
159+
// количество равно, но списки не равны
160+
// попробуем оставить в списках только уникальные элементы
161+
// если останется больше 0 (а странно будет, если не так), то сравним по первому элементу
162+
var left = new HashSet<>(content);
163+
var right = new HashSet<>(multiLanguageString.content);
164+
left.removeAll(right);
165+
right.removeAll(left);
166+
if (left.isEmpty() && right.isEmpty()) {
167+
return 0; // хз как это получилось
168+
} else if (left.isEmpty()) {
169+
return -1;
170+
} else if (right.isEmpty()) {
171+
return 1;
172+
} else {
173+
var leftOne = left.iterator().next();
174+
var rightOne = right.iterator().next();
175+
return leftOne.compareTo(rightOne);
176+
}
177+
}
178+
179+
private MultiLanguageString intern() {
180+
return interner.intern(this);
181+
}
182+
183+
@EqualsAndHashCode
184+
public static class Entry implements Comparable<Entry> {
185+
@Getter
186+
private final String langKey;
187+
@Getter
188+
private final String value;
189+
private static final StringInterner stringInterner = new StringInterner();
190+
private static final GenericInterner<Entry> interner = new GenericInterner<>();
191+
192+
private Entry(String langKey, String value) {
193+
this.langKey = stringInterner.intern(langKey);
194+
this.value = value;
195+
}
196+
197+
public static Entry create(String langKey, String value) {
198+
return new Entry(langKey, value).intern();
199+
}
200+
201+
@Override
202+
public int compareTo(@Nullable Entry entry) {
203+
if (entry == null) {
204+
return 1;
205+
}
206+
207+
if (this.equals(entry)) {
208+
return 0;
209+
}
210+
211+
int compareResult = langKey.compareTo(entry.langKey);
212+
if (compareResult != 0) {
213+
return compareResult;
214+
}
215+
216+
return value.compareTo(entry.value);
217+
}
218+
219+
private Entry intern() {
220+
return interner.intern(this);
221+
}
118222
}
119223
}

0 commit comments

Comments
 (0)