From 46ffb9d779cb27f83d7a7bd426ee453d4df3d1f0 Mon Sep 17 00:00:00 2001 From: wangyong Date: Sat, 15 Jan 2022 18:04:34 +0800 Subject: [PATCH] Add TS associative container Signed-off-by: wangyong --- container/BUILD.gn | 8 + container/hashmap/js_hashmap.ts | 171 +++ container/hashmap/native_module_hashmap.cpp | 67 ++ container/hashset/js_hashset.ts | 137 +++ container/hashset/native_module_hashset.cpp | 67 ++ container/lightweightmap/js_lightweightmap.ts | 221 ++++ .../native_module_lightweightmap.cpp | 68 ++ container/lightweightset/js_lightweightset.ts | 184 +++ .../native_module_lightweightset.cpp | 68 ++ container/plainarray/js_plainarray.ts | 164 +++ .../plainarray/native_module_plainarray.cpp | 68 ++ container/struct/js_struct.ts | 1046 +++++++++++++++++ container/struct/native_module_struct.cpp | 68 ++ container/treemap/js_treemap.ts | 203 ++++ container/treemap/native_module_treemap.cpp | 68 ++ container/treeset/js_treeset.ts | 194 +++ container/treeset/native_module_treeset.cpp | 68 ++ 17 files changed, 2870 insertions(+) create mode 100644 container/hashmap/js_hashmap.ts create mode 100644 container/hashmap/native_module_hashmap.cpp create mode 100644 container/hashset/js_hashset.ts create mode 100644 container/hashset/native_module_hashset.cpp create mode 100644 container/lightweightmap/js_lightweightmap.ts create mode 100644 container/lightweightmap/native_module_lightweightmap.cpp create mode 100644 container/lightweightset/js_lightweightset.ts create mode 100644 container/lightweightset/native_module_lightweightset.cpp create mode 100644 container/plainarray/js_plainarray.ts create mode 100644 container/plainarray/native_module_plainarray.cpp create mode 100644 container/struct/js_struct.ts create mode 100644 container/struct/native_module_struct.cpp create mode 100644 container/treemap/js_treemap.ts create mode 100644 container/treemap/native_module_treemap.cpp create mode 100644 container/treeset/js_treeset.ts create mode 100644 container/treeset/native_module_treeset.cpp diff --git a/container/BUILD.gn b/container/BUILD.gn index 24bf50b..2f09e2a 100644 --- a/container/BUILD.gn +++ b/container/BUILD.gn @@ -24,6 +24,14 @@ container_names = [ "linkedlist", "list", "stack", + "struct", + "treemap", + "treeset", + "hashmap", + "hashset", + "lightweightmap", + "lightweightset", + "plainarray", ] # compile .ts to .js. diff --git a/container/hashmap/js_hashmap.ts b/container/hashmap/js_hashmap.ts new file mode 100644 index 0000000..028af88 --- /dev/null +++ b/container/hashmap/js_hashmap.ts @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +declare function requireNapi(s: string): any; + +let flag = false; +let fastHashMap = undefined; +let arkPritvate = globalThis["ArkPrivate"] || undefined; +if (arkPritvate !== undefined) { + fastHashMap = arkPritvate.Load(arkPritvate.HashMap); +} else { + flag = true; +} + +if (flag || fastHashMap === undefined) { + const HashMapAbility = requireNapi("struct"); + interface IterableIterator { + next: () => { + value: T | undefined; + done: boolean; + }; + } + + class HandlerHashMap { + set(target: HashMap, p: any, value: any): boolean { + if (p in target) { + target[p] = value; + return true; + } + return false; + } + defineProperty(target: HashMap, p: any): boolean { + throw new Error("Can't defineProperty on HashMap Object"); + } + deleteProperty(target: HashMap, p: any): boolean { + throw new Error("Can't deleteProperty on HashMap Object"); + } + setPrototypeOf(target: HashMap, p: any): boolean { + throw new Error("Can't setPrototype on HashMap Object"); + } + } + + class HashMap extends HashMapAbility.DictionaryClass { + constructor() { + super(); + return new Proxy(this, new HandlerHashMap()); + } + + get length() { + return this.memberNumber; + } + isEmpty(): boolean { + return this.memberNumber === 0; + } + hasKey(key: K): boolean { + return super.hasKey(key); + } + hasValue(value: V): boolean { + return super.Values().indexOf(value) > -1; + } + get(key: K): V { + let result = super.getValueByKey(key); + if (result === undefined) + throw new Error("this hashmap don't find the key"); + return result; + } + setAll(map: HashMap): void { + let memebers = this.keyValueArray; + for (let i = 0; i < memebers.length; i++) { + map.put(memebers[i].key, memebers[i].value); + } + } + set(key: K, value: V): Object { + return super.put(key, value); + } + remove(key: K): V { + let result = this.removeMember(key); + if (result === null) { + throw new Error("The removed element does not exist in this container"); + } + return result; + } + clear(): void { + super.clear(); + } + keys(): IterableIterator { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? data.keyValueArray[count++].key : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + values(): IterableIterator { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? data.keyValueArray[count++].value : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + replace(key: K, newValue: V): boolean { + return super.replaceMember(key, newValue); + } + forEach(callbackfn: (value?: V, key?: K, map?: HashMap) => void, + thisArg?: Object): void { + let tagetArray = this.keyValueArray; + for (let i = 0; i < tagetArray.length; i++) { + callbackfn.call(thisArg, tagetArray[i].value, tagetArray[i].key, this); + } + } + entries(): IterableIterator<[K, V]> { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? data.keyValueArray[count++].entry() : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + [Symbol.iterator](): IterableIterator<[K, V]> { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? data.keyValueArray[count++].entry() : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + } + + Object.freeze(HashMap); + fastHashMap = HashMap; +} + +export default { + HashMap: fastHashMap, +}; \ No newline at end of file diff --git a/container/hashmap/native_module_hashmap.cpp b/container/hashmap/native_module_hashmap.cpp new file mode 100644 index 0000000..4da9b03 --- /dev/null +++ b/container/hashmap/native_module_hashmap.cpp @@ -0,0 +1,67 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_hashmap_js_start[]; +extern const char _binary_js_hashmap_js_end[]; +extern const char _binary_hashmap_abc_start[]; +extern const char _binary_hashmap_abc_end[]; + +namespace OHOS::Util { +static napi_value HashMapInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_hashmap_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_hashmap_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_hashmap_js_end - _binary_js_hashmap_js_start; + } +} +extern "C" +__attribute__((visibility("default"))) void NAPI_hashmap_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_hashmap_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_hashmap_abc_end - _binary_hashmap_abc_start; + } +} + +static napi_module hashMapModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = HashMapInit, + .nm_modname = "HashMap", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&hashMapModule); +} +} diff --git a/container/hashset/js_hashset.ts b/container/hashset/js_hashset.ts new file mode 100644 index 0000000..3d268b4 --- /dev/null +++ b/container/hashset/js_hashset.ts @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare function requireNapi(s: string): any; + +let flag = false; +let fastHashSet = undefined; +let arkPritvate = globalThis["ArkPrivate"] || undefined; +if (arkPritvate !== undefined) { + fastHashSet = arkPritvate.Load(arkPritvate.HashSet); +} else { + flag = true; +} +if (flag || fastHashSet === undefined) { + const HashSetAbility = requireNapi("struct"); + interface IterableIterator { + next: () => { + value: T | undefined; + done: boolean; + }; + } + + class HandlerHashSet { + set(target: HashSet, p: any, value: any): boolean { + if (p in target) { + target[p] = value; + return true; + } + return false; + } + defineProperty(target: HashSet, p: any): boolean { + throw new Error("Can't defineProperty on HashMap Object"); + } + deleteProperty(target: HashSet, p: any): boolean { + throw new Error("Can't deleteProperty on HashMap Object"); + } + setPrototypeOf(target: HashSet, p: any): boolean { + throw new Error("Can't setPrototype on HashMap Object"); + } + } + + class HashSet extends HashSetAbility.DictionaryClass { + constructor() { + super(); + return new Proxy(this, new HandlerHashSet()); + } + + get length() { + return this.memberNumber; + } + isEmpty(): boolean { + return this.memberNumber === 0; + } + has(value: T): boolean { + return super.hasKey(value); + } + add(value: T): boolean { + if (this.has(value)) return false; + return this.put(value); + } + remove(value: T): boolean { + if (this.removeMember(value) !== null) return true; + return false; + } + clear(): void { + super.clear(); + } + forEach(callbackfn: (value?: T, key?: T, set?: HashSet) => void, + thisArg?: Object): void { + let tagetArray = this.keyValueArray; + for (let i = 0; i < tagetArray.length; i++) { + callbackfn.call(thisArg, tagetArray[i].key, tagetArray[i].key, this); + } + } + values(): IterableIterator { + let _this = this; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].key : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + entries(): IterableIterator<[T, T]> { + let _this = this; + let count = 0; + return { + next: function () { + var done = count >= _this.memberNumber; + var value = !done ? _this.keyValueArray[count++].entry() : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + [Symbol.iterator](): IterableIterator { + let _this = this; + let count = 0; + return { + next: function () { + var done = count >= _this.memberNumber; + var value = !done ? _this.keyValueArray[count++].key : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + } + + Object.freeze(HashSet); + fastHashSet = HashSet; +} + +export default { + HashSet: fastHashSet, +}; diff --git a/container/hashset/native_module_hashset.cpp b/container/hashset/native_module_hashset.cpp new file mode 100644 index 0000000..ef8999e --- /dev/null +++ b/container/hashset/native_module_hashset.cpp @@ -0,0 +1,67 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_hashset_js_start[]; +extern const char _binary_js_hashset_js_end[]; +extern const char _binary_hashset_abc_start[]; +extern const char _binary_hashset_abc_end[]; + +namespace OHOS::Util { +static napi_value HashSetInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_hashset_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_hashset_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_hashset_js_end - _binary_js_hashset_js_start; + } +} +extern "C" +__attribute__((visibility("default"))) void NAPI_hashset_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_hashset_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_hashset_abc_end - _binary_hashset_abc_start; + } +} + +static napi_module hashSetModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = HashSetInit, + .nm_modname = "HashSet", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&hashSetModule); +} +} diff --git a/container/lightweightmap/js_lightweightmap.ts b/container/lightweightmap/js_lightweightmap.ts new file mode 100644 index 0000000..b066522 --- /dev/null +++ b/container/lightweightmap/js_lightweightmap.ts @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +declare function requireNapi(s: string): any; + +let flag = false; +let fastLightWeightMap = undefined; +let arkPritvate = globalThis["ArkPrivate"] || undefined; +if (arkPritvate !== undefined) { + fastLightWeightMap = arkPritvate.Load(arkPritvate.LightWeightMap); +} else { + flag = true; +} + +if (flag || fastLightWeightMap === undefined) { + const LightWeightAbility = requireNapi("struct"); + interface IterableIterator { + next: () => { + value: T | undefined; + done: boolean; + }; + } + + class HandlerLightWeightMap { + set(target: LightWeightMap, p: any, value: any): boolean { + if (p in target) { + target[p] = value; + return true; + } + return false; + } + defineProperty(target: LightWeightMap, p: any): boolean { + throw new Error("Can't defineProperty on LightWeightMap Object"); + } + deleteProperty(target: LightWeightMap, p: any): boolean { + throw new Error("Can't deleteProperty on LightWeightMap Object"); + } + setPrototypeOf(target: LightWeightMap, p: any): boolean { + throw new Error("Can't setPrototype on LightWeightMap Object"); + } + } + + class LightWeightMap extends LightWeightAbility.LightWeightClass { + constructor() { + super(); + return new Proxy(this, new HandlerLightWeightMap()); + } + + get length() { + return this.memberNumber; + } + hasAll(map: LightWeightMap): boolean { + if (map.memberNumber > this.memberNumber) return false; + if (LightWeightAbility.isIncludeToArray(this.members.keys, map.members.keys) && + LightWeightAbility.isIncludeToArray(this.members.values, map.members.values)) { + return true; + } + return false; + } + hasKey(key: K): boolean { + return this.members.keys.indexOf(key) > -1; + } + hasValue(value: V): boolean { + return this.members.values.indexOf(value) > -1; + } + increaseCapacityTo(minimumCapacity: number): void { + super.ensureCapacity(minimumCapacity); + } + entries(): IterableIterator<[K, V]> { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? [data.members.keys[count], data.members.values[count]] as [K, V] : undefined; + count++; + return { + done: done, + value: value, + }; + }, + }; + } + get(key: K): V { + let index = this.getIndexByKey(key); + return this.members.values[index]; + } + getIndexOfKey(key: K): number { + return this.getIndexByKey(key); + } + getIndexOfValue(value: V): number { + return this.members.values.indexOf(value); + } + isEmpty(): boolean { + return this.memberNumber === 0; + } + getKeyAt(index: number): K { + return this.members.keys[index]; + } + keys(): IterableIterator { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? data.members.keys[count] : undefined; + count++; + return { + done: done, + value: value, + }; + }, + }; + } + setAll(map: LightWeightMap): void { + if (map.memberNumber === 0) { + map.members.hashs = this.members.hashs.slice(); + map.members.keys = this.members.keys.slice(); + map.members.values = this.members.values.slice(); + map.memberNumber = this.memberNumber; + } else { + for (let i = 0; i < this.memberNumber; i++) { + map.addmember(this.members.keys[i], this.members.values[i]); + } + } + } + set(key: K, value: V): Object { + this.addmember(key, value); + return this; + } + remove(key: K): V { + return this.deletemember(key); + } + removeAt(index: number): boolean { + if (index > this.memberNumber--) return false; + this.members.hashs.splice(index, 1); + this.members.values.splice(index, 1); + this.members.keys.splice(index, 1); + this.memberNumber--; + return true; + } + clear(): void { + if (this.memberNumber != 0 || this.capacity > 8) { + this.members.hashs = []; + this.members.keys = []; + this.members.values = []; + this.memberNumber = 0; + this.capacity = 8; + } + } + setValueAt(index: number, newValue: V): boolean { + if (index > this.memberNumber || this.members.values[index] === undefined) return false; + this.members.values[index] = newValue; + return true; + } + forEach(callbackfn: (value?: V, key?: K, map?: LightWeightMap) => void, + thisArg?: Object): void { + let _this = this; + for (let i = 0; i < _this.memberNumber; i++) { + callbackfn.call(thisArg, _this.members.values[i], _this.members.keys[i], _this); + } + } + [Symbol.iterator](): IterableIterator<[K, V]> { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? [data.members.keys[count], data.members.values[count]] as [K, V] : undefined; + count++; + return { + done: done, + value: value, + }; + }, + }; + } + toString(): string { + let result = new Array(); + for (let i = 0; i < this.memberNumber; i++) { + result.push(this.members.keys[i] + ":" + this.members.values[i]); + } + return result.join(","); + } + getValueAt(index: number): V { + return this.members.values[index] as V; + } + values(): IterableIterator { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? data.members.values[count] : undefined; + count++; + return { + done: done, + value: value, + }; + }, + }; + } + } + + Object.freeze(LightWeightMap); + fastLightWeightMap = LightWeightMap; +} +export default { + LightWeightMap: fastLightWeightMap, +}; diff --git a/container/lightweightmap/native_module_lightweightmap.cpp b/container/lightweightmap/native_module_lightweightmap.cpp new file mode 100644 index 0000000..ec32936 --- /dev/null +++ b/container/lightweightmap/native_module_lightweightmap.cpp @@ -0,0 +1,68 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_lightweightmap_js_start[]; +extern const char _binary_js_lightweightmap_js_end[]; +extern const char _binary_lightweightmap_abc_start[]; +extern const char _binary_lightweightmap_abc_end[]; + +namespace OHOS::Util { +static napi_value LightWeightMapInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_lightweightmap_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_lightweightmap_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_lightweightmap_js_end - _binary_js_lightweightmap_js_start; + } +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_lightweightmap_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_lightweightmap_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_lightweightmap_abc_end - _binary_lightweightmap_abc_start; + } +} + +static napi_module lightWeightMapModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = LightWeightMapInit, + .nm_modname = "LightWeightMap", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&lightWeightMapModule); +} +} diff --git a/container/lightweightset/js_lightweightset.ts b/container/lightweightset/js_lightweightset.ts new file mode 100644 index 0000000..b43182f --- /dev/null +++ b/container/lightweightset/js_lightweightset.ts @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +declare function requireNapi(s: string): any; + +let flag = false; +let fastLightWeightSet = undefined; +let arkPritvate = globalThis["ArkPrivate"] || undefined; +if (arkPritvate !== undefined) { + fastLightWeightSet = arkPritvate.Load(arkPritvate.LightWeightSet); +} else { + flag = true; +} + +if (flag || fastLightWeightSet === undefined) { + const LightWeightAbility = requireNapi("struct"); + interface IterableIterator { + next: () => { + value: T | undefined; + done: boolean; + }; + } + + class HandlerLightWeightSet { + set(target: LightWeightSet, p: any, value: any): boolean { + if (p in target) { + target[p] = value; + return true; + } + return false; + } + defineProperty(target: LightWeightSet, p: any): boolean { + throw new Error("Can't LightWeightSet on HashMap Object"); + } + deleteProperty(target: LightWeightSet, p: any): boolean { + throw new Error("Can't LightWeightSet on HashMap Object"); + } + setPrototypeOf(target: LightWeightSet, p: any): boolean { + throw new Error("Can't LightWeightSet on HashMap Object"); + } + } + + class LightWeightSet extends LightWeightAbility.LightWeightClass { + constructor() { + super(); + return new Proxy(this, new HandlerLightWeightSet()); + } + + get length() { + return this.memberNumber; + } + add(obj: T): boolean { + if (this.members.keys.indexOf(obj) > 0) return false; + this.addmember(obj); + return true; + } + addAll(set: LightWeightSet): boolean { + let change = false; + if (set.memberNumber == 0) { + set.memberNumber = this.memberNumber; + set.members.hashs = this.members.hashs.slice(); + set.members.keys = this.members.keys.slice(); + set.members.values = this.members.values.slice(); + set.memberNumber = this.memberNumber; + change = true; + } else { + for (let i = 0; i < this.memberNumber; i++) { + change = set.add(this.members.keys[i]) || change; + } + } + return change; + } + hasAll(set: LightWeightSet): boolean { + if (set.memberNumber > this.memberNumber) return false; + if (LightWeightAbility.isIncludeToArray(this.members.keys, set.members.keys)) { + return true; + } + return false; + } + has(key: T): boolean { + return this.members.keys.indexOf(key) > -1; + } + equal(obj: Object): boolean { + if (this.memberNumber === 0) return false; + if (obj.toString() === this.members.keys.toString()) return true; + return false; + } + increaseCapacityTo(minimumCapacity: number): void { + super.ensureCapacity(minimumCapacity); + } + getIndexOf(key: T): number { + return super.getIndexByKey(key); + } + isEmpty(): boolean { + return this.memberNumber === 0; + } + remove(key: T): T { + return super.deletemember(key); + } + removeAt(index: number): boolean { + if (index > this.memberNumber--) return false; + this.members.hashs.splice(index, 1); + this.members.values.splice(index, 1); + this.members.keys.splice(index, 1); + this.memberNumber--; + return true; + } + clear(): void { + if (this.memberNumber != 0 || this.capacity > 8) { + this.members.hashs = []; + this.members.keys = []; + this.members.values = []; + this.memberNumber = 0; + this.capacity = 8; + } + } + forEach(callbackfn: (value?: T, key?: T, set?: LightWeightSet) => void, + thisArg?: Object): void { + let _this = this; + for (let i = 0; i < _this.memberNumber; i++) { + callbackfn.call(thisArg, _this.members.keys[i], _this.members.keys[i], _this); + } + } + [Symbol.iterator](): IterableIterator { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var value = !done ? data.members.keys[count] : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + toString(): string { + return this.members.keys.join(","); + } + toArray(): Array { + return this.members.keys.slice(); + } + getValueAt(index: number): T { + return this.members.keys[index]; + } + values(): IterableIterator { + return this.members.keys.values() as IterableIterator; + } + entries(): IterableIterator<[T, T]> { + let data = this; + let count = 0; + return { + next: function () { + var done = count >= data.memberNumber; + var tempValue = data.members.keys[count]; + var value = !done ? ([tempValue, tempValue] as [T, T]) : undefined; + count++; + return { + done: done, + value: value, + }; + }, + }; + } + } + + Object.freeze(LightWeightSet); + fastLightWeightSet = LightWeightSet; +} +export default { + LightWeightSet: fastLightWeightSet, +}; diff --git a/container/lightweightset/native_module_lightweightset.cpp b/container/lightweightset/native_module_lightweightset.cpp new file mode 100644 index 0000000..577efbc --- /dev/null +++ b/container/lightweightset/native_module_lightweightset.cpp @@ -0,0 +1,68 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_lightweightset_js_start[]; +extern const char _binary_js_lightweightset_js_end[]; +extern const char _binary_lightweightset_abc_start[]; +extern const char _binary_lightweightset_abc_end[]; + +namespace OHOS::Util { +static napi_value LightWeightSetInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_lightweightset_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_lightweightset_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_lightweightset_js_end - _binary_js_lightweightset_js_start; + } +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_lightweightset_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_lightweightset_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_lightweightset_abc_end - _binary_lightweightset_abc_start; + } +} + +static napi_module lightWeightSetModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = LightWeightSetInit, + .nm_modname = "LightWeightSet", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&lightWeightSetModule); +} +} diff --git a/container/plainarray/js_plainarray.ts b/container/plainarray/js_plainarray.ts new file mode 100644 index 0000000..7f453da --- /dev/null +++ b/container/plainarray/js_plainarray.ts @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +declare function requireNapi(s: string): any; + +let flag = false; +let fastPlainArray = undefined; +let arkPritvate = globalThis["ArkPrivate"] || undefined; +if (arkPritvate !== undefined) { + fastPlainArray = arkPritvate.Load(arkPritvate.PlainArray); +} else { + flag = true; +} + +if (flag || fastPlainArray === undefined) { + const PlainAbility = requireNapi("struct"); + interface IterableIterator { + next: () => { + value: T | undefined; + done: boolean; + }; + } + + class HandlerPlainArray { + set(target: PlainArray, p: any, value: any): boolean { + if (p in target) { + target[p] = value; + return true; + } + return false; + } + defineProperty(target: PlainArray, p: any): boolean { + throw new Error("Can't PlainArray on HashMap Object"); + } + deleteProperty(target: PlainArray, p: any): boolean { + throw new Error("Can't PlainArray on HashMap Object"); + } + setPrototypeOf(target: PlainArray, p: any): boolean { + throw new Error("Can't PlainArray on HashMap Object"); + } + } + class PlainArray extends PlainAbility.PlainArrayClass { + constructor() { + super(); + return new Proxy(this, new HandlerPlainArray()); + } + + get length() { + return this.memberNumber; + } + add(key: number, value: T): void { + if(typeof key !== "number") { + throw new Error("PlainArray's only number is allowed"); + } + this.addmember(key, value); + } + clear(): void { + if (this.memberNumber != 0) { + this.members.keys = []; + this.members.values = []; + this.memberNumber = 0; + } + } + clone(): PlainArray { + let clone = new PlainArray(); + clone.memberNumber = this.memberNumber; + clone.members.keys = this.members.keys.slice(); + clone.members.values = this.members.values.slice(); + + return clone; + } + has(key: number): boolean { + return this.binarySearch_Plain(key) > -1; + } + get(key: number): T { + let index = this.binarySearch_Plain(key); + if (index < 0) throw new Error("Key error found"); + return this.members.values[index]; + } + getIndexOfKey(key: number): number { + let result = this.binarySearch_Plain(key); + return result < 0 ? -1 : result; + } + getIndexOfValue(value: T): number { + return this.members.values.indexOf(value); + } + isEmpty(): boolean { + return this.memberNumber === 0; + } + getKeyAt(index: number): number { + return this.members.keys[index]; + } + remove(key: number): T { + let index = this.binarySearch_Plain(key); + if (index < 0) throw new Error(" element not in this plainarray"); + return this.deletemember(index); + } + removeAt(index: number): T { + if (index >= this.memberNumber || index < 0) throw new Error("index not in this plainarray range"); + return this.deletemember(index); + } + removeRangeFrom(index: number, size: number): number { + if (index >= this.memberNumber || index < 0) throw new Error("index not in this plainarray range"); + let safeSize = (this.memberNumber - (index + size) < 0) ? this.memberNumber - size : size; + this.deletemember(index, safeSize); + return safeSize; + } + setValueAt(index: number, value: T): void { + if (index >= 0 && index < this.memberNumber) { + this.members.values[index] = value; + } else { + throw new Error("index Out Of Bounds"); + } + } + toString(): string { + let result = new Array(); + for (let i = 0; i < this.memberNumber; i++) { + result.push(this.members.keys[i] + ":" + this.members.values[i]); + } + return result.join(","); + } + getValueAt(index: number): T { + return this.members.values[index]; + } + forEach(callbackfn: (value: T, index?: number, PlainArray?: PlainArray) => void, + thisArg?: Object): void { + for (let i = 0; i < this.memberNumber; i++) { + callbackfn.call(thisArg, this.members.values[i], this.members.keys[i]); + } + } + [Symbol.iterator](): IterableIterator<[number, T]> { + let _this = this; + let count = 0; + return { + next: function () { + var done = count >= _this.memberNumber; + var value = !done ? [_this.members.keys[count], _this.members.values[count]] as [number, T] : undefined; + count++; + return { + done: done, + value: value, + }; + }, + }; + } + + } + Object.freeze(PlainArray); + fastPlainArray = PlainArray; +} +export default { + PlainArray: fastPlainArray, +}; diff --git a/container/plainarray/native_module_plainarray.cpp b/container/plainarray/native_module_plainarray.cpp new file mode 100644 index 0000000..d33c50b --- /dev/null +++ b/container/plainarray/native_module_plainarray.cpp @@ -0,0 +1,68 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_plainarray_js_start[]; +extern const char _binary_js_plainarray_js_end[]; +extern const char _binary_plainarray_abc_start[]; +extern const char _binary_plainarray_abc_end[]; + +namespace OHOS::Util { +static napi_value PlainArrayInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_plainarray_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_plainarray_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_plainarray_js_end - _binary_js_plainarray_js_start; + } +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_plainarray_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_plainarray_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_plainarray_abc_end - _binary_plainarray_abc_start; + } +} + +static napi_module plainArrayModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = PlainArrayInit, + .nm_modname = "PlainArray", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&plainArrayModule); +} +} diff --git a/container/struct/js_struct.ts b/container/struct/js_struct.ts new file mode 100644 index 0000000..99b4671 --- /dev/null +++ b/container/struct/js_struct.ts @@ -0,0 +1,1046 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +function hashCode(element: any): number { + let str = String(element); + let hash = 0; + if (hash === 0 && str.length > 0) { + for (let i = 0; i < str.length; i++) { + let char = str.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; + } + } + return hash; +} + +function insert(a: Array, index: number, value: T) { + for (let i = a.length; i > index; i--) { + a[i] = a[i - 1]; + } + a[index] = value; +} + +enum ComparResult { + LESS_THAN = -1, + BIGGER_THAN = 1, + EQUALS = 0 +} + +function compareToString(string1: String, string2: String) { + let len1 = string1.length; + let len2 = string2.length; + let lim = (len1 > len2 ? len2 : len1); + + let k = 0; + while (k < lim) { + if (string1.charCodeAt(k) === string2.charCodeAt(k)) { + k++; + if(k === lim) { + return len1 > len2 ? ComparResult.BIGGER_THAN : ComparResult.LESS_THAN; + } + continue; + } + return string1.charCodeAt(k) > string2.charCodeAt(k) ? ComparResult.BIGGER_THAN : ComparResult.LESS_THAN; + } + + throw new Error("this function run error"); + +} + +// There is type judgment in comparison, and the input parameter type cannot be defined directly +function currencyCompare(a: any, b: any, compareFn?: Function): number { + if (a === b) return ComparResult.EQUALS; + if (compareFn != undefined) { + return compareFn(a, b) ? ComparResult.BIGGER_THAN : ComparResult.LESS_THAN; + } + if (typeof a === "number" && typeof b === "number") { + if (a > b) { + return ComparResult.BIGGER_THAN; + } else { + return ComparResult.LESS_THAN; + } + } else if (typeof a === "string" && typeof b === "string") { + return compareToString(a, b); + } else if (typeof a === "string" && typeof b === "number") { + return ComparResult.BIGGER_THAN; + } else if (typeof a === "number" && typeof b === "string") { + return ComparResult.LESS_THAN; + } else if (a instanceof Pair && b instanceof Pair) { + return currencyCompare(a.key, b.key); + } + throw new Error("This form of comparison is not supported"); +} + +function isIncludeToArray(array1: Array, array2: Array): boolean { + let newlist = array1.filter((val) => { + return array2.indexOf(val) > -1; + }) + if (newlist.length == array2.length) return true; + return false; +} + + +class Pair{ + key: K; + value: V; + constructor(key: K, value: V = key as unknown as V) { + this.key = key; + this.value = value; + } + + entry(): [K, V] { + return [this.key, this.value]; + } + + toString() { + return `[#${this.key}: ${this.value}]`; + } +} + +class PlainArrayMembers { + keys: Array; + values: Array; + constructor() { + this.keys = []; + this.values = []; + } +} +class PlainArrayClass { + protected memberNumber: number; + protected members: PlainArrayMembers; + constructor() { + this.memberNumber = 0; + this.members = new PlainArrayMembers(); + } + + protected addmember(key: number, value: T) { + let index = this.binarySearch_Plain(key); + if (index > 0) { + this.members.keys[index] = key; + this.members.values[index] = value; + } else { + index = ~index; + insert(this.members.keys, index, key); + insert(this.members.values, index, value); + this.memberNumber++; + } + } + + protected deletemember(index: number, safeSize: number = 1): T { + this.memberNumber -= safeSize; + this.members.keys.splice(index, safeSize); + let removeValue = this.members.values.splice(index, safeSize)[0]; + return removeValue; + } + + protected binarySearch_Plain(key: number, startIndex: number = 0, endIndex: number = this.memberNumber): number { + let low = startIndex; + let high = endIndex - 1; + + while (low <= high) { + let mid = (low + high) >>> 1; + let midVal = this.members.keys[mid]; + if (midVal < key) { + low = mid + 1; + } else { + if (midVal <= key) { + return mid; + } + high = mid - 1; + } + } + + return -(low + 1); + } + +} + +class LightWeightMembers { + hashs: Array; + keys: Array; + values: Array; + constructor() { + this.hashs = []; + this.keys = []; + this.values = []; + } +} +class LightWeightClass { + protected memberNumber: number; + protected members: LightWeightMembers; + protected capacity: number = 8; + constructor() { + this.memberNumber = 0; + this.members = new LightWeightMembers(); + } + + protected addmember(key: K, value: V = key as unknown as V) { + let hash = hashCode(key); + let index = this.binarySearch_LightWeight(hash); + if (index > 0) { + this.members.keys[index] = key; + this.members.values[index] = value; + } else { + index = ~index; + insert(this.members.hashs, index, hash); + insert(this.members.keys, index, key); + insert(this.members.values, index, value); + this.memberNumber++; + } + + if (this.capacity < this.memberNumber) this.ensureCapacity(1); + } + + protected getIndexByKey(key: K): number { + let hash = hashCode(key); + let index = this.binarySearch_LightWeight(hash); + if (index < 0 || index >= this.memberNumber) return -1; + return index; + } + + protected deletemember(key: K): V { + let index = this.getIndexByKey(key); + if (index < 0) + throw new Error("don't find the key in lightweight"); + this.memberNumber--; + this.members.hashs.splice(index, 1); + this.members.keys.splice(index, 1); + return this.members.values.splice(index, 1)[0]; + } + + protected ensureCapacity(addCapacity: number = 1) { + // The TS terminal does not need to realize the capacity expansion function + // capacity ensure consistency with ark side + let tempCapacity = this.capacity + addCapacity; + while (this.capacity < tempCapacity) { + this.capacity = 2 * this.capacity; + } + } + + protected getIndex(key: K): number { + let hash = hashCode(key); + let index = this.binarySearch_LightWeight(hash); + if (index < 0) index = ~index; + return index; + } + + protected keyArray(): Array { + let resultArray: Array = []; + for (let i = 0; i < this.memberNumber; i++) { + resultArray.push(this.members[i].key); + } + return resultArray; + } + + protected binarySearch_LightWeight(hash: number, startIndex: number = 0, endIndex: number = this.memberNumber): number { + let low = startIndex; + let high = endIndex - 1; + + while (low <= high) { + let mid = (low + high) >>> 1; + let midVal = this.members.hashs[mid]; + if (midVal < hash) { + low = mid + 1; + } else { + if (midVal <= hash) { + return mid; + } + high = mid - 1; + } + } + + return -(low + 1); + } + +} + +type RBTreeNodeColor = "black" | "red"; +const BLACK = "black"; +const RED = "red"; +class RBTreeNode extends Pair{ + color: RBTreeNodeColor; + left: RBTreeNode | null; + right: RBTreeNode | null; + parent: RBTreeNode | null; + constructor( + key: K, + value?: V, + color: RBTreeNodeColor = RED, + parent: RBTreeNode | null = null, + left: RBTreeNode | null = null, + right: RBTreeNode | null = null + ) { + super(key, value); + this.color = color; + this.left = left; + this.right = right; + this.parent = parent; + } + +} +class RBTreeClass { + private _root: RBTreeNode | null; + public memberNumber: number; + private _isChange: boolean; + private _treeArray: Array>; + constructor(root: RBTreeNode | null = null) { + this._root = root; + this.memberNumber = 0; + this._isChange = true; + this._treeArray = []; + } + + get keyValueArray() { + let result = this.recordByMinToMax(); + return result; + } + + addNode(key: K, value: V = key as unknown as V): RBTreeClass { + if (this._root === null) { + this._root = new RBTreeNode(key, value) + this.setColor(this._root, BLACK); + this.memberNumber++; + this._isChange = true; + } else { + this.addProcess(key, value) + } + + return this; + } + + addProcess(key: K, value: V): RBTreeClass { + let leafNode: RBTreeNode | null = this._root; + let parentNode: RBTreeNode = this._root as RBTreeNode; + let comp: number = 0; + + while (leafNode !== null) { + parentNode = leafNode; + comp = currencyCompare(leafNode.key, key); + if (comp === 0) { + leafNode.value = value; + return this; + } else if (comp < 0) { + leafNode = leafNode.right; + } else { + leafNode = leafNode.left; + } + } + + leafNode = new RBTreeNode(key, value) + leafNode.parent = parentNode; + + if (comp < 0) { + parentNode.right = leafNode; + } else { + parentNode.left = leafNode; + } + + this.insertRebalance(leafNode); + this.memberNumber++; + this._isChange = true; + + return this; + } + + removeNode(key: K): V | null { + const removeNode = this.getNode(key); + if (removeNode === null) { + return null; + } else { + let result = removeNode.value; + this.removeNodeProcess(removeNode); + return result; + } + } + + removeNodeProcess(removeNode: RBTreeNode) { + if (removeNode.left !== null && removeNode.right !== null) { + let successor = removeNode.right; + while (successor.left !== null) { + successor = successor.left; + } + removeNode = successor; + } + + let replacementNode = (removeNode.right === null ? removeNode.left : removeNode.right); + if (replacementNode !== null) { + replacementNode.parent = removeNode.parent; + if (removeNode.parent === null) { + this._root = replacementNode; + } else if (removeNode === removeNode.parent.right) { + removeNode.parent.right = replacementNode; + } else if (removeNode === removeNode.parent.left) { + removeNode.parent.left = replacementNode; + } + if (this.getColor(removeNode) === BLACK) { + this.deleteRebalance(replacementNode) + } + } else if (removeNode.parent === null) { + // removeNode.right = null; removeNode.left = null + this._root = null; + } else { + if (this.getColor(removeNode) === BLACK) { + this.deleteRebalance(removeNode) + } + + if (removeNode === removeNode.parent.left) { + removeNode.parent.left = null; + } else if (removeNode === removeNode.parent.right) { + removeNode.parent.right = null; + } + } + + this.memberNumber--; + this._isChange = true; + } + + getNode(key: K): RBTreeNode | null { + if (this._root === null) + return null; + let removeNode: RBTreeNode | null = this._root; + while (removeNode !== null && removeNode.key !== key) { + removeNode = removeNode.key > key ? removeNode.left : removeNode.right; + } + return removeNode; + } + + findNode(value: V): RBTreeNode | null { + let tempNode: RBTreeNode | null = null; + this.recordByMinToMax(); + for (let i = 0; i < this.memberNumber; i++) { + if (this._treeArray[i].value === value) tempNode = this._treeArray[i]; + break; + } + return tempNode; + } + + firstNode(): RBTreeNode | null { + let tempNode: RBTreeNode | null = this._root; + while (tempNode !== null && tempNode.left !== null) { + tempNode = tempNode.left; + } + return tempNode; + } + + lastNode(): RBTreeNode | null { + let tempNode: RBTreeNode | null = this._root; + while (tempNode !== null && tempNode.right !== null) { + tempNode = tempNode.right; + } + return tempNode; + } + + isEmpty(): boolean { + return this._root === null; + } + + setAll(map: RBTreeClass) { + this.recordByMinToMax(); + for(let i = 0; i < this.memberNumber; i++) { + map.addNode(this._treeArray[i].key, this._treeArray[i].value); + } + } + + clearTree() { + this._root = null; + this.memberNumber = 0; + } + + // inorder traversal + private recordByMinToMax(): Array> { + if (!this._isChange) return this._treeArray; + let stack = []; + this._treeArray = []; + let node = this._root; + while (node != null || stack.length) { + while (node != null) { + stack.push(node); + node = node.left; + } + let tempNode = stack.pop(); + if (tempNode === undefined || tempNode === null) + throw new Error("this function run error"); + node = tempNode; + this._treeArray.push(node); + node = node.right; + } + + this._isChange = false; + this.memberNumber = this._treeArray.length; + return this._treeArray; + } + + private lRotate(datumPointNode: RBTreeNode): RBTreeClass { + let newTopNode = datumPointNode.right; + if (newTopNode === null) + throw new Error("[rotate right error]: the right child node of the base node === null") + + datumPointNode.right = newTopNode.left; + datumPointNode.right !== null ? datumPointNode.right.parent = datumPointNode : ""; + + newTopNode.parent = datumPointNode.parent; + if (datumPointNode.parent === null) { + this._root = newTopNode; + } else if (datumPointNode.parent.left === datumPointNode) { + datumPointNode.parent.left = newTopNode; + } else if (datumPointNode.parent.right === datumPointNode) { + datumPointNode.parent.right = newTopNode; + } + + datumPointNode.parent = newTopNode; + newTopNode.left = datumPointNode; + + return this; + } + + private rRotate(datumPointNode: RBTreeNode): RBTreeClass { + const newTopNode = datumPointNode.left; + if (newTopNode === null) { + throw new Error("[rotate right error]: the left child node of the base node === null") + } + + datumPointNode.left = newTopNode.right; + datumPointNode.left !== null ? datumPointNode.left.parent = datumPointNode : ""; + newTopNode.parent = datumPointNode.parent + if (datumPointNode.parent === null) { + this._root = newTopNode; + } else if (datumPointNode === datumPointNode.parent.left) { + datumPointNode.parent.left = newTopNode; + } else if (datumPointNode === datumPointNode.parent.right) { + datumPointNode.parent.right = newTopNode; + } + + datumPointNode.parent = newTopNode; + newTopNode.right = datumPointNode; + + return this; + } + + private insertRebalance(fixNode: RBTreeNode): RBTreeClass { + let parentNode = fixNode.parent; + while (this.getColor(parentNode) === RED && + parentNode !== null && + parentNode.parent !== null) { + let grandpaNode = parentNode && parentNode.parent; + if (parentNode === grandpaNode.left && + this.getColor(grandpaNode.right) === BLACK && + fixNode === parentNode.left) { + this + .setColor(parentNode, BLACK) + .setColor(grandpaNode, RED) + .rRotate(grandpaNode) + break; + } else if (parentNode === grandpaNode.left && + this.getColor(grandpaNode.right) === BLACK && + fixNode === parentNode.right) { + this + .setColor(fixNode, BLACK) + .setColor(grandpaNode, RED) + .lRotate(parentNode) + .rRotate(grandpaNode) + break; + } else if (parentNode === grandpaNode.right && + this.getColor(grandpaNode.left) === BLACK && + fixNode === parentNode.left) { + this + .setColor(fixNode, BLACK) + .setColor(grandpaNode, RED) + .rRotate(parentNode) + .lRotate(grandpaNode) + break; + } else if (parentNode === grandpaNode.right && + this.getColor(grandpaNode.left) === BLACK && + fixNode === parentNode.right) { + this + .setColor(parentNode, BLACK) + .setColor(grandpaNode, RED) + .lRotate(grandpaNode) + break; + } else if ((parentNode === grandpaNode.right && this.getColor(grandpaNode.left) === RED) || + (parentNode === grandpaNode.left && this.getColor(grandpaNode.right) === RED)) { + this + .setColor(parentNode, BLACK) + .setColor(parentNode === grandpaNode.left ? grandpaNode.right : grandpaNode.left, BLACK) + .setColor(grandpaNode, RED) + fixNode = grandpaNode; + parentNode = fixNode.parent; + } else { + throw new Error("Exceptions after adding") + } + } + this._root ? this._root.color = BLACK : ""; + return this; + } + + private deleteRebalance(fixNode: RBTreeNode) { + while (this.getColor(fixNode) === BLACK && fixNode !== this._root && fixNode.parent) { + let sibling: RBTreeNode | null; + if (fixNode === fixNode.parent.left) { + sibling = fixNode.parent.right; + if (this.getColor(sibling) === RED) { + this + .setColor(fixNode.parent, RED) + .setColor(sibling, BLACK) + .lRotate(fixNode.parent) + sibling = fixNode.parent.right; + } + if (sibling === null) { + throw new Error('Error sibling node is null') + } + if (this.getColor(sibling.left) === BLACK && this.getColor(sibling.right) === BLACK) { + this.setColor(sibling, RED) + fixNode = fixNode.parent + } else if (this.getColor(sibling.left) === RED && this.getColor(sibling.right) === BLACK) { + this + .setColor(sibling, RED) + .setColor(sibling.left, BLACK) + .rRotate(sibling); + sibling = fixNode.parent.right + if (sibling === null) { + throw new Error('Error sibling node is empty') + } + this + .setColor(sibling, fixNode.parent.color) + .setColor(fixNode.parent, BLACK) + .setColor(sibling.right, BLACK) + .lRotate(fixNode.parent); + break; + } else if (this.getColor(sibling.right) === RED) { + this + .setColor(sibling, fixNode.parent.color) + .setColor(fixNode.parent, BLACK) + .setColor(sibling.right, BLACK) + .lRotate(fixNode.parent); + break; + } else { + throw new Error("Adjust the error after the error is deleted") + } + } else { + sibling = fixNode.parent.left; + if (this.getColor(sibling) === RED) { + this + .setColor(sibling, BLACK) + .setColor(fixNode.parent, RED) + .rRotate(fixNode.parent); + sibling = fixNode.parent.left; + } + if (sibling === null) { + throw new Error('Error sibling node is null') + } + if (this.getColor(sibling.left) === BLACK && this.getColor(sibling.right) === BLACK) { + this + .setColor(sibling, RED) + fixNode = fixNode.parent; + } else if (this.getColor(sibling.left) === BLACK && this.getColor(sibling.right) === RED) { + this + .setColor(sibling, RED) + .setColor(sibling.right, BLACK) + .lRotate(sibling); + sibling = fixNode.parent.left; + if (sibling === null) { + throw new Error('Adjust the error after the error is deleted') + } + this + .setColor(sibling, fixNode.parent.color) + .setColor(fixNode.parent, BLACK) + .setColor(sibling.left, BLACK) + .rRotate(fixNode.parent); + break; + } else if (this.getColor(sibling.left) === RED) { + this + .setColor(sibling, fixNode.parent.color) + .setColor(fixNode.parent, BLACK) + .setColor(sibling.left, BLACK) + .rRotate(fixNode.parent); + break; + } else { + throw new Error("Adjust the error after the error is deleted") + } + } + } + this.setColor(fixNode, BLACK) + } + + private getColor(node: RBTreeNode | null): RBTreeNodeColor { + return node === null ? BLACK : node.color; + } + + private setColor(node: RBTreeNode | null, color: RBTreeNodeColor): RBTreeClass { + if (node === null) { + throw new Error("Wrong color setting") + } else { + node.color = color + } + return this; + } + +} + +const MAX_CAPACITY = 1 << 30; +const LOADER_FACTOR = 0.75; +class DictionaryClass { + private _tableLink: { [hashIndex: number]: LinkedList> | RBTreeClass }; + protected memberNumber: number; + private _isChange: boolean; + private _memberArray: Array>; + private _capacity: number; + + constructor() { + this._tableLink = {}; + this.memberNumber = 0; + this._isChange = true; + this._memberArray = []; + this._capacity = 16; + } + + get keyValueArray() { + let result = this.keyValues(); + return result; + } + + protected getHashIndex(key: K): number { + let h; + let hash = ((key === null) ? 0 : ((h = hashCode(key)) ^ (h >>> 16))); + this.expandCapacity(); + let n = this.power(this._capacity); + return (n - 1) & hash; + } + + private power(size: number) { + let n = 1; + let temp = size; + while (temp >>> 1 != 1) { + n++; + temp = temp >>> 1; + } + return n; + } + + private keyValues(): Pair[] { + if (!this._isChange) return this._memberArray; + this._memberArray = []; + const keys = Object.keys(this._tableLink).map((item) => parseInt(item)); + for (let i = 0; i < keys.length; i++) { + const members = this._tableLink[keys[i]]; + + if (members instanceof RBTreeClass) { + let tempArray = members.keyValueArray; + for (let i = 0; i < members.memberNumber; i++) { + this._memberArray.push(new Pair(tempArray[i].key, tempArray[i].value)); + } + } else { + if (members != null && !members.isEmpty()) { + let current = members.getHead(); + while (current != null) { + this._memberArray.push(current.element); + current = current.next; + } + } + } + } + this.memberNumber = this._memberArray.length; + let valuePairs = this._memberArray; + return valuePairs; + } + + protected expandCapacity() { + // The TS terminal does not need to realize the _capacity expansion function + // _capacity ensure consistency with ark side + while (this._capacity < this.memberNumber / LOADER_FACTOR && this._capacity < MAX_CAPACITY) { + this._capacity = 2 * this._capacity; + } + } + + protected put(key: K, value: V = key as unknown as V): boolean { + if (key != null && value != null) { + this._isChange = true; + this.memberNumber++; + + const position = this.getHashIndex(key); + let members = this._tableLink[position]; + + if (members instanceof LinkedList && members.count >= 8) { + let newElement = new RBTreeClass(); + let current = members.getHead(); + while (current != null || current != undefined) { + if (!(current.element instanceof Pair)) + throw new Error("this hashtable member save error"); + newElement.addNode(current.element.key, current.element.value); + current = current.next; + } + newElement.addNode(key, value); + this._tableLink[position] = newElement; + return true; + } else if (members instanceof RBTreeClass) { + members.addNode(key, value); + this._tableLink[position] = members; + return true; + } else { + if (this._tableLink[position] == null) { + members = new LinkedList>(); + } + if (!this.replaceMember(key, value)) { + members.push(new Pair(key, value)); + this._tableLink[position] = members; + } + return true; + } + } + + return false; + } + + protected replaceMember(key: K, value: V = key as unknown as V): boolean { + const position = this.getHashIndex(key); + const members = this._tableLink[position] as LinkedList>; + if (members === null || members === undefined) return false; + let current = members.getHead(); + while (current != null || current != undefined) { + if (current.element.key === key) { + current.element.value = value; + return true; + } + current = current.next; + } + return false; + } + + protected getValueByKey(key: K): V | undefined { + const position = this.getHashIndex(key); + const members = this._tableLink[position]; + if (members instanceof RBTreeClass) { + let resultNode = members.getNode(key); + if (resultNode === null) return undefined; + return resultNode.value; + } else { + if (members != null && !members.isEmpty()) { + members as LinkedList>; + let current = members.getHead(); + while (current != null) { + if (current.element.key === key) { + return current.element.value; + } + current = current.next; + } + } + } + return undefined; + } + + protected removeMember(key: K): V | null{ + const position = this.getHashIndex(key); + const members = this._tableLink[position]; + if (members instanceof RBTreeClass) { + let result = members.removeNode(key); + if (result != null) { + this._isChange = true; + this.memberNumber--; + return result; + } + } else { + if (members != null && !members.isEmpty()) { + let current = members.getHead(); + while (current != null) { + if (current.element.key === key) { + const result = current.element.value; + members.remove(current.element); + if (members.isEmpty()) { + delete this._tableLink[position]; + } + this._isChange = true; + this.memberNumber--; + return result; + } + current = current.next; + } + } + } + return null; + } + + protected clear() { + this._tableLink = {}; + this.memberNumber = 0; + this._isChange = true; + } + + protected hasKey(key: K): boolean { + const position = this.getHashIndex(key); + const members = this._tableLink[position]; + if (members === null || members === undefined) return false; + if (members instanceof RBTreeClass) { + return members.getNode(key) !== null; + } + let current = members.getHead(); + while (current != null && current != undefined) { + if (current.element.key === key) { + return true; + } + current = current.next; + } + return false; + } + + protected setAll(map: DictionaryClass): void { + let memebers = this.keyValues(); + for (let i = 0; i < memebers.length; i++) { + map.put(memebers[i].key, memebers[i].value); + } + } + + protected Values(): V[] { + const values = []; + const valuePairs = this.keyValues(); + for (let i = 0; i < valuePairs.length; i++) { + values.push(valuePairs[i].value); + } + return values; + } +} + +class Node{ + element: T; + next: Node | null; + constructor(element: T, next: Node | null = null) { + this.element = element; + this.next = next; + } +} +class LinkedList { + public count: number; + protected next: Node | null; + protected head: Node | null; + + constructor() { + this.count = 0; + this.next = null; + this.head = null; + } + + push(element: T) { + const node = new Node(element); + let current; + if (this.head == null) { + this.head = node; + } else { + current = this.head; + while (current.next != null) { + current = current.next; + } + current.next = node; + } + this.count++; + } + + removeAt(index: number) { + if (index >= 0 && index < this.count) { + let current = this.head; + if (index === 0 && current != null) { + this.head = current.next; + } else { + const previous = this.getElementAt(index--); + if (previous !== null) { + current = previous.next; + previous.next = (current === null ? null : current.next); + } + } + if (current !== null) { + this.count--; + return current.element; + } + } + return undefined; + } + + getElementAt(index: number) { + if (index > 0 && index < this.count) { + let current = this.head; + for (let i = 0; i < index && current != null; i++) { + current = current.next; + } + return current; + } + return null; + } + + insert(element: T, index: number) { + if (index >= 0 && index <= this.count) { + const node = new Node(element); + if (index === 0) { + node.next = this.head; + this.head = node; + } else { + const previous = this.getElementAt(index--); + if (previous === null) + throw new Error("data storage error"); + node.next = previous.next; + previous.next = node; + } + this.count++; + return true; + } + return false; + } + + indexOf(element: T) { + let current = this.head; + for (let i = 0; i < this.count && current != null; i++) { + if (currencyCompare(element, current.element)) { + return i; + } + current = current.next; + } + return -1; + } + + remove(element: T) { + this.removeAt(this.indexOf(element)); + } + + clear() { + this.head = null; + this.count = 0; + } + + isEmpty() { + return this.count === 0; + } + + getHead() { + return this.head; + } + toString() { + if (this.head == null) { + return ""; + } + let objString = `${this.head.element}`; + let current = this.head.next; + for (let i = 1; i < this.count && current != null; i++) { + objString = `${objString}, ${current.element}`; + current = current.next; + } + return objString; + } +} + + +export default { + isIncludeToArray, + LightWeightClass, + PlainArrayClass, + RBTreeClass, + DictionaryClass +} + diff --git a/container/struct/native_module_struct.cpp b/container/struct/native_module_struct.cpp new file mode 100644 index 0000000..01c0311 --- /dev/null +++ b/container/struct/native_module_struct.cpp @@ -0,0 +1,68 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_struct_js_start[]; +extern const char _binary_js_struct_js_end[]; +extern const char _binary_struct_abc_start[]; +extern const char _binary_struct_abc_end[]; + +namespace OHOS::Util { +static napi_value StructInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_struct_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_struct_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_struct_js_end - _binary_js_struct_js_start; + } +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_struct_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_struct_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_struct_abc_end - _binary_struct_abc_start; + } +} + +static napi_module structModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = StructInit, + .nm_modname = "struct", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&structModule); +} +} diff --git a/container/treemap/js_treemap.ts b/container/treemap/js_treemap.ts new file mode 100644 index 0000000..bbf7749 --- /dev/null +++ b/container/treemap/js_treemap.ts @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +declare function requireNapi(s: string): any; + +let flag = false; +let fastTreeMap = undefined; +let arkPritvate = globalThis["ArkPrivate"] || undefined; +if (arkPritvate !== undefined) { + fastTreeMap = arkPritvate.Load(arkPritvate.TreeMap); +} else { + flag = true; +} +if (flag || fastTreeMap === undefined) { + const RBTreeAbility = requireNapi("struct") + interface IterableIterator { + next: () => { + value: T | undefined; + done: boolean; + }; + } + + class HandlerTreeMap { + set(target: TreeMap, p: any, value: any): boolean { + if (p in target) { + target[p] = value; + return true; + } + return false; + } + defineProperty(target: TreeMap, p: any): boolean { + throw new Error("Can't defineProperty on TreeMap Object"); + } + deleteProperty(target: TreeMap, p: any): boolean { + throw new Error("Can't deleteProperty on TreeMap Object"); + } + setPrototypeOf(target: TreeMap, p: any): boolean { + throw new Error("Can't setPrototype on TreeMap Object"); + } + } + + class TreeMap { + private _constitute: any; + constructor() { + this._constitute = new RBTreeAbility.RBTreeClass(); + return new Proxy(this, new HandlerTreeMap()); + } + + get length() { + return this._constitute.memberNumber; + } + hasKey(key: K): boolean { + return this._constitute.getNode(key) !== null; + } + hasValue(value: V): boolean { + return this._constitute.findNode(value) !== null; + } + get(key: K): V | null { + let tempNode = this._constitute.getNode(key); + if (tempNode === null) + return null; + return tempNode.value; + } + getFirstKey(): K { + let tempNode = this._constitute.firstNode(); + if (tempNode === null) + throw new Error("don't find this key,this tree is null"); + return tempNode.key; + } + getLastKey(): K { + let tempNode = this._constitute.lastNode(); + if (tempNode === null) + throw new Error("don't find this key,this tree is null"); + return tempNode.key; + } + setAll(map: TreeMap) { + this._constitute.setAll(map._constitute); + } + set(key: K, value: V): Object { + // If the user enters key other than number and string, a comparison function is required + return this._constitute.addNode(key, value); + } + remove(key: K): V | null { + return this._constitute.removeNode(key); + } + clear() { + this._constitute.clearTree(); + } + getLowerKey(key: K): K { + let tempNode = this._constitute.getNode(key); + if (tempNode === null) + throw new Error("don't find this key,this node is undefine"); + if (tempNode.left !== null) return tempNode.left.key; + let node = tempNode; + while (node.parent !== null) { + if (node.parent.right === node) return node.parent.key; + node = node.parent; + } + throw new Error("don't find a key meet the conditions"); + } + getHigherKey(key: K): K { + let tempNode = this._constitute.getNode(key); + + if (tempNode === null) + throw new Error("don't find this key,this node is undefine"); + if (tempNode.right !== null) return tempNode.right.key; + let node = tempNode; + while (node.parent !== null) { + if (node.parent.left === node) return node.parent.key; + node = node.parent; + } + + throw new Error("don't find a key meet the conditions"); + } + keys(): IterableIterator { + let _this = this._constitute; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].key : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + values(): IterableIterator { + let _this = this._constitute; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].value as V : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + replace(key: K, newValue: V): boolean { + let targetNode = this._constitute.getNode(key); + if (targetNode === null) return false; + targetNode.value = newValue; + return true; + } + forEach(callbackfn: (value?: V, key?: K, map?: TreeMap) => void, + thisArg?: Object): void { + let _this = this._constitute; + let tagetArray = _this.keyValueArray; + for (let i = 0; i < _this.memberNumber; i++) { + callbackfn.call(thisArg, tagetArray[i].value as V, tagetArray[i].key); + } + } + entries(): IterableIterator<[K, V]> { + let _this = this._constitute; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].entry() : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + [Symbol.iterator](): IterableIterator<[K, V]> { + let _this = this._constitute; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].entry() : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + } + + Object.freeze(TreeMap); + fastTreeMap = TreeMap; +} +export default { + TreeMap: fastTreeMap, +}; \ No newline at end of file diff --git a/container/treemap/native_module_treemap.cpp b/container/treemap/native_module_treemap.cpp new file mode 100644 index 0000000..a67b2fe --- /dev/null +++ b/container/treemap/native_module_treemap.cpp @@ -0,0 +1,68 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_treemap_js_start[]; +extern const char _binary_js_treemap_js_end[]; +extern const char _binary_treemap_abc_start[]; +extern const char _binary_treemap_abc_end[]; + +namespace OHOS::Util { +static napi_value TreeMapInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_treemap_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_treemap_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_treemap_js_end - _binary_js_treemap_js_start; + } +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_treemap_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_treemap_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_treemap_abc_end - _binary_treemap_abc_start; + } +} + +static napi_module treeMapModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = TreeMapInit, + .nm_modname = "TreeMap", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&treeMapModule); +} +} diff --git a/container/treeset/js_treeset.ts b/container/treeset/js_treeset.ts new file mode 100644 index 0000000..50cc6ce --- /dev/null +++ b/container/treeset/js_treeset.ts @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +declare function requireNapi(s: string): any; + +let flag = false; +let fastTreeSet = undefined; +let arkPritvate = globalThis["ArkPrivate"] || undefined; +if (arkPritvate !== undefined) { + fastTreeSet = arkPritvate.Load(arkPritvate.TreeSet); +} else { + flag = true; +} + +if (flag || fastTreeSet === undefined) { + const RBTreeAbility = requireNapi("struct"); + interface IterableIterator { + next: () => { + value: T | undefined; + done: boolean; + }; + } + + class HandlerTreeSet { + set(target: TreeSet, p: any, value: any): boolean { + if (p in target) { + target[p] = value; + return true; + } + return false; + } + defineProperty(target: TreeSet, p: any): boolean { + throw new Error("Can't TreeSet on HashMap Object"); + } + deleteProperty(target: TreeSet, p: any): boolean { + throw new Error("Can't TreeSet on HashMap Object"); + } + setPrototypeOf(target: TreeSet, p: any): boolean { + throw new Error("Can't TreeSet on HashMap Object"); + } + } + + class TreeSet { + private _constitute: any; + constructor() { + this._constitute = new RBTreeAbility.RBTreeClass(); + return new Proxy(this, new HandlerTreeSet()); + } + + get length() { + return this._constitute.memberNumber; + } + isEmpty(): boolean { + return this._constitute.isEmpty(); + } + has(value: T): boolean { + return this._constitute.getNode(value) !== null; + } + add(value: T): boolean { + this._constitute.addNode(value); + return true; + } + remove(value: T): boolean { + let result = this._constitute.removeNode(value); + return result !== null; + } + clear() { + this._constitute.clearTree(); + } + getFirstValue(): T { + let tempNode = this._constitute.firstNode(); + if (tempNode === null) + throw new Error("don't find this key,this tree is null"); + return tempNode.key; + } + getLastValue(): T { + let tempNode = this._constitute.lastNode(); + if (tempNode === null) + throw new Error("don't find this key,this tree is null"); + return tempNode.key; + } + getLowerValue(key: T): T { + let tempNode = this._constitute.getNode(key); + + if (tempNode === null) + throw new Error("don't find this key,this node is undefine"); + if (tempNode.left !== null) return tempNode.left.key; + let node = tempNode; + while (node.parent !== null) { + if (node.parent.right === node) return node.parent.key; + node = node.parent; // node.parent.left === node is true; + } + + throw new Error("don't find a key meet the conditions"); + } + getHigherValue(key: T): T { + let tempNode = this._constitute.getNode(key); + + if (tempNode === null) + throw new Error("don't find this key,this node is undefine"); + if (tempNode.right !== null) return tempNode.right.key; + let node = tempNode; + while (node.parent !== null) { + if (node.parent.left === node) return node.parent.key; + node = node.parent; // node.parent.right === node is true; + } + + throw new Error("don't find a key meet the conditions"); + } + popFirst(): T { + let firstNode = this._constitute.firstNode(); + if (firstNode === null) + throw new Error("don't find first node,this tree is empty"); + let value = firstNode.value; + this._constitute.removeNodeProcess(firstNode); + return value as T; + } + popLast(): T { + let lastNode = this._constitute.lastNode(); + if (lastNode === null) + throw new Error("don't find last node,this tree is empty"); + let value = lastNode.value; + this._constitute.removeNodeProcess(lastNode); + return value as T; + } + values(): IterableIterator { + let _this = this._constitute; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].value as T : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + forEach(callbackfn: (value?: T, key?: T, set?: TreeSet) => void, + thisArg?: Object): void { + let _this = this._constitute; + let tagetArray = _this.keyValueArray; + for (let i = 0; i < _this.memberNumber; i++) { + callbackfn.call(thisArg, tagetArray[i].value as T, tagetArray[i].key); + } + } + entries(): IterableIterator<[T, T]> { + let _this = this._constitute; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].entry() : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + [Symbol.iterator](): IterableIterator { + let _this = this._constitute; + let i = 0; + return { + next: function () { + var done = i >= _this.memberNumber; + var value = !done ? _this.keyValueArray[i++].key : undefined; + return { + done: done, + value: value, + }; + }, + }; + } + } + + Object.freeze(TreeSet); + fastTreeSet = TreeSet; +} +export default { + TreeSet: fastTreeSet, +}; diff --git a/container/treeset/native_module_treeset.cpp b/container/treeset/native_module_treeset.cpp new file mode 100644 index 0000000..12142e9 --- /dev/null +++ b/container/treeset/native_module_treeset.cpp @@ -0,0 +1,68 @@ + /* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils/log.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" + +extern const char _binary_js_treeset_js_start[]; +extern const char _binary_js_treeset_js_end[]; +extern const char _binary_treeset_abc_start[]; +extern const char _binary_treeset_abc_end[]; + +namespace OHOS::Util { +static napi_value TreeSetInit(napi_env env, napi_value exports) +{ + return exports; +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_treeset_GetJSCode(const char **buf, int *bufLen) +{ + if (buf != nullptr) { + *buf = _binary_js_treeset_js_start; + } + + if (bufLen != nullptr) { + *bufLen = _binary_js_treeset_js_end - _binary_js_treeset_js_start; + } +} + +extern "C" +__attribute__((visibility("default"))) void NAPI_treeset_GetABCCode(const char** buf, int* buflen) +{ + if (buf != nullptr) { + *buf = _binary_treeset_abc_start; + } + if (buflen != nullptr) { + *buflen = _binary_treeset_abc_end - _binary_treeset_abc_start; + } +} + +static napi_module treeSetModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = TreeSetInit, + .nm_modname = "TreeSet", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__ ((constructor)) void RegisterModule() +{ + napi_module_register(&treeSetModule); +} +} -- Gitee