1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import { mapClass } from './libvbar-m-dxmap.so'
/**
 * In-memory Key-Value Store Module (dxMap)
 *
 * Features:
 * - Provides a topic-based, in-memory key-value storage.
 * - Thread-safe: Data can be safely accessed and modified from multiple JavaScript threads.
 * - Supports storing various data types (string, number, boolean, object, array) by automatically serializing/deserializing them.
 *
 * Usage:
 * - First, get a map instance for a specific topic using `map.get('myTopic')`.
 * - Then, use the instance's methods (`put`, `get`, `has`, `del`, etc.) to manage data within that topic.
 *
 * @example
 * import map from 'dxMap';
 *
 * // Get an instance for the 'user' topic
 * const userMap = map.get('user');
 *
 * // Put some data
 * userMap.put('name', 'John Doe');
 * userMap.put('age', 30);
 * userMap.put('isActive', true);
 * userMap.put('roles', ['admin', 'editor']);
 *
 * // Get data
 * const name = userMap.get('name'); // "John Doe"
 *
 * // Check if a key exists
 * const hasAge = userMap.has('age'); // true
 *
 * // Delete a key
 * userMap.del('isActive');
 *
 * // Get all keys for the topic
 * const allKeys = userMap.keys(); // ['name', 'age', 'roles']
 *
 * Doc/Demo: https://github.com/DejaOS/DejaOS
 */
const mapObj = new mapClass();
 
const map = {
    /**
     * Gets a map instance for a given topic name.
     * Each topic is a separate namespace for keys.
     * @param {string} name - The name of the topic. Must not be null or empty.
     * @returns {{keys: (function(): string[]), get: (function(string): *), has: (function(string): boolean), put: (function(string, *): boolean), del: (function(string): boolean), destroy: (function(): boolean)}} An object with methods to interact with the map for the specified topic.
     * @throws {Error} If the name is null or empty.
     */
    get: function (name) {
        if (!name || name.length == 0) {
            throw new Error("dxMap.get:name should not be null or empty")
        }
        //第一次put会自动创建实例
        return {
            /**
             * Retrieves all keys within the current topic.
             * @returns {string[]} An array of all keys for the topic. Returns an empty array if the topic is empty or does not exist.
             */
            keys: function () {
                let all = mapObj.keys(name)
                return all == null ? [] : all
            },
            /**
             * Retrieves the value associated with a key within the current topic.
             * The returned value will be deserialized to its original type (number, boolean, object, array, or string).
             * @param {string} key - The key to retrieve. Must not be null or empty.
             * @returns {*} The value associated with the key, or `undefined` if the key does not exist.
             * @throws {Error} If the key is null or empty.
             */
            get: function (key) {
                if (!key || key.length < 1) {
                    throw new Error("The 'key' parameter cannot be null or empty")
                }
                // put空字符串,get会是null
                let value = mapObj.get(name, key)
                // C layer returns null if not found. JS layer should propagate this.
                if (value === null) {
                    return undefined; // Return undefined for non-existent keys, a common JS pattern.
                }
                return _parseString(value)
            },
            /**
             * Checks if a key exists within the current topic.
             * @param {string} key - The key to check. Must not be null or empty.
             * @returns {boolean} `true` if the key exists, `false` otherwise.
             * @throws {Error} If the key is null or empty.
             */
            has: function (key) {
                if (!key || key.length < 1) {
                    throw new Error("The 'key' parameter cannot be null or empty")
                }
                return mapObj.has(name, key)
            },
            /**
             * Inserts or updates a key-value pair within the current topic.
             * The value will be automatically serialized.
             * If `value` is `null` or `undefined`, the key will be deleted.
             * @param {string} key - The key to set. Must not be null or empty.
             * @param {*} value - The value to associate with the key. Supported types: string, number, boolean, object, array. Functions are not supported.
             * @returns {boolean} Returns `true` on success.
             * @throws {Error} If the key is null or empty, or if the value is a function.
             */
            put: function (key, value) {
                if (!key || key.length < 1) {
                    throw new Error("The 'key' parameter cannot be null or empty")
                }
                // Implement "set null/undefined to delete" logic.
                if (value === null || value === undefined) {
                    return mapObj.delete(name, key);
                }
                return mapObj.insert(name, key, _stringifyValue(value))
            },
            /**
             * Deletes a key-value pair from the current topic.
             * @param {string} key - The key to delete. Must not be null or empty.
             * @returns {boolean} `true` if the key was found and deleted, `false` otherwise.
             * @throws {Error} If the key is null or empty.
             */
            del: function (key) {
                if (!key || key.length < 1) {
                    throw new Error("The 'key' parameter cannot be null or empty")
                }
                return mapObj.delete(name, key)
            },
            /**
             * Destroys the entire topic, deleting all its keys and freeing associated memory.
             * After calling destroy, the instance should not be used anymore.
             * @returns {boolean} Returns `true` on success.
             */
            destroy: function () {
                return mapObj.destroy(name)
            },
        }
    }
 
}
/**
 * Serializes a value into a string with a type prefix.
 * @private
 * @param {*} value - The value to serialize.
 * @returns {string} The serialized string.
 */
function _stringifyValue(value) {
    const type = typeof value
    if (type === 'string') {
        return value
    }
    if (type === 'number') {
        return '#n#' + value
    }
    if (type === 'boolean') {
        return '#b#' + value
    }
    if (type === 'object') {
        // 如果是对象,进一步判断是否为数组
        if (Array.isArray(value)) {
            return '#a#' + JSON.stringify(value);
        }// else if (value === null) { 前面已经规避了null的情况
        return '#o#' + JSON.stringify(value)
    }
    if (type === 'function') {
        throw new Error("The 'value' parameter should not be function")
    }
}
/**
 * Deserializes a string with a type prefix back to its original value.
 * @private
 * @param {string} str - The string to deserialize.
 * @returns {*} The deserialized value.
 */
function _parseString(str) {
    if (str.startsWith('#n#')) {
        // 解析数字
        const numberStr = str.substring(3);
        return numberStr.includes('.') ? parseFloat(numberStr) : parseInt(numberStr, 10);
    } else if (str.startsWith('#b#')) {
        // 解析布尔值
        return str.substring(3) === 'true';
    } else if (str.startsWith('#a#')) {
        // 解析数组
        return JSON.parse(str.substring(3));
    } else if (str.startsWith('#o#')) {
        // 解析对象
        return JSON.parse(str.substring(3));
    } else {
        // 默认情况下,将字符串返回
        return str;
    }
}
export default map;