//table 线程共享表 namespace thread var t_call = ..thread.call class table{ ctor( name,clear=false){ if(!name) { name = ..thread.call("_$(_thread_var_getName)"); } if( ( ! ..thread.get(name ) || clear) ){ ..thread.set(name,{}) } this[-0xFFFFFFFF] = name; }; @meta; } var tableFunc = { shift=1; unshift=1; right=1; slice=1; sort=1; unpack=1; range=1; next=1; splice=1; tostring=1; insert=1; pop=1; concat=1; push=1; count=1; reverse=1; left=1; append=1; remove=1; clear=1; splice=1; } table.array = function(...){ var t = table(...); t_call("_$__table_setType",,t[-0xFFFFFFFF],"array"); return t; } table.meta = { _get = function(k,ownerCall){ if(ownerCall===null){ return t_call("_$__table_getItem", ,owner[-0xFFFFFFFF],k ) } if(type(k)==="string" && k[1]!='_'#){ var f = table.meta[k]; if(f) return f; if(tableFunc[k]){ return function(...){ return t_call("_$__table_call",k,owner[-0xFFFFFFFF],... ) } } if(k==="name") return owner[-0xFFFFFFFF]; if(k==="length"){ return t_call("_$__table_length",,owner[-0xFFFFFFFF]); } } return t_call("_$__table_getItem", ,owner[-0xFFFFFFFF],k ) } _set = function(k,v,ownerAttr){ if( ownerAttr && (tableFunc[k] || table.meta[k] || k==="name"|| k==="length")){ error("不能修改保留属性,请改用下标操作符修改共享表键值。",2) } t_call("_$__table_setItem", ,owner[-0xFFFFFFFF],k,v ) } _serialize = function(kernelCall){ if(kernelCall) return `global.import('thread.table') : thread.table("`++owner[-0xFFFFFFFF]++`")`; else { return owner.tostring(); } } _json = function(){ var t = ..thread.get(owner[-0xFFFFFFFF]); if( owner.length !== null ) t@ = {_type="array"} return t; } get = function(k){ return t_call("_$__table_getItem", ,owner[-0xFFFFFFFF],k) } set = function(k,v){ t_call("_$__table_setItem", ,owner[-0xFFFFFFFF],k,v ) } getByPath = function(k){ return t_call("_$__table_getByPath", ,owner[-0xFFFFFFFF],k) } setByPath = function(k,v){ t_call("_$__table_setByPath", ,owner[-0xFFFFFFFF],k,v ) } lenByPath = function(k,v){ t_call("_$__table_lenByPath", ,owner[-0xFFFFFFFF],k,v ) } len = function(){ return t_call("_$__table_len", ,owner[-0xFFFFFFFF] ) } append = function(...){ return t_call("_$__table_append", ,owner[-0xFFFFFFFF],... ) } assign = function(...){ return t_call("_$__table_assign", ,owner[-0xFFFFFFFF],... ) } each = function(){ return owner.next,owner } release = function(){ ..thread.call("_$(_thread_var_release)",,owner[-0xFFFFFFFF]); ..thread.set(owner[-0xFFFFFFFF],null); } add = function(k,v){ return ..thread.call("_$__table_add",,owner[-0xFFFFFFFF],k,v); } } table.meta.getByNamespace = table.meta.get; table.meta.setByNamespace = table.meta.set; lock("INIT.THREAD.CALL.{7EC7B22E-F1A6-4AA7-B5A3-4741C583AA00}") if( ! get("_$__table_call" ) ){ set( "_$__table_call", function( name,...){ var t = global[name]; if(t)return table[owner]( t,...); } ) set( "_$__table_getItem", function( name,k){ var t = global[name]; if(t)return t[k]; } ) set( "_$__table_setItem", function( name,k,v){ var t = global[name]; if(t)t[k] = v; } ) set( "_$__table_getByPath", function( name,k){ var t = global[name]; if(t)return ( ..table.get(k,t) ); } ) set( "_$__table_setByPath", function( name,k,v){ var t = global[name]; if(t)..table.set(k,v,t); } ) set( "_$__table_lenByPath", function( name,k){ var t = global[name]; if(t)return #..table.get(k,t); } ) set( "_$__table_len", function( name ){ var t = global[name]; if(t) return #(t); return 0; } ) set( "_$__table_setType", function( name,tp ){ var t = global[name]; if(t && !t@)t@ = { _type = tp }; } ) set( "_$__table_length", function( name ){ var t = global[name]; if(#t || ( t@ && t@._type == "array") ) return #t; } ) set( "_$__table_append", function( name,... ){ var t = global[name]; if(t) ..table.append(t,...); } ) set( "_$__table_add", function( name,k,v ){ var t = global[name]; t[k] = (t[k]:0) + v; return t[k]; } ) set( "_$__table_assign", function( name,... ){ var t = global[name]; if(t) ..table.assign(t,...); } ) } unlock("INIT.THREAD.CALL.{7EC7B22E-F1A6-4AA7-B5A3-4741C583AA00}") /**details(用法说明) 线程共享表用于读写多线程共享值,以简化 thread.get,thread.set 的操作。 线程共享表本质上只是线程共享数据代理对象,自身并不存储这些线程共享数据。 线程共享表(thread.table )基本规则: - 每次读取共享表的成员都会在当前线程复制一个新的副本。 - 写入直接表的直接成员才会写入线程共享资源。 - 不要将普通表直接覆盖替换线程共享表自身,应当存为子表 - 线程共享表的子表并非也是共享表,修改子表的成员并不能更新父级线程共享表。 - 线程共享表的下标操作符被重载为读写共享资源,不会与共享表的同名方法、属性发生冲突。 - 线程共享表的成员操作符虽然也能读写共享资源,但要避免覆盖同名的共享表方法与属性。 - 获取共享数组长度应当用线程共享表对象的 len 函数而不是 # 操作符。 使用 thread.table 的示例 aardio 代码: ```aardio //注意先导入 thread.table 库再创建 thread.table 对象。 var thrdTable = thread.table() //用下标读写键值,键名与对象的属性、函数名同名不会冲突。 thrdTable["b"] = 34; thrdTable["c"]= 56; //可以读写普通表,但子表并不是线程共享表。 thrdTable["d"] = {}; //每次读取 thrdTable.d 都会得到新的副本 var localData = thrdTable["d"]; //修改 localData 不会自动会同步到线程共享资源。 localData.tab = { name = "name" } //下面这样只是修改子表的临时副本,子表不是线程共享表 thrdTable.d.tab = { name = "name" } //只有修改线程共享表的直接成员,才会自动同步到线程共享资源 thrdTable["d"] = localData; //注意 # 操作符不适合用于线程共享表 var len = #thrdTable //应当用 len 函数或 length 属性获取共享数组长度 len = thrdTable.len(); // 也可以用 thrdTable. //线程共享表可作为线程函数的参数直接传入其他线程函数。 thread.invoke( function(tab){ var localData = thrdTable["d"]; },thrdTable ) ``` end details**/ /**intellisense() thread.table = 多线程共享表。\n这是标准库模块,需要导入才能用。\n线程共享表用于读写多线程共享值,以简化 thread.get,thread.set 的操作。\n注意线程共享表本质上只是线程共享数据代理对象,自身并不存储这些线程共享数据。\n- 每次读取共享表的成员都会在当前线程复制一个新的副本。\n- 写入直接表的直接成员才会写入线程共享资源。\n- 不要将普通表直接覆盖替换线程共享表自身,应当存为子表\n- 线程共享表的子表并非也是共享表,修改子表的成员并不能更新父级线程共享表。\n- 线程共享表的下标操作符被重载为读写共享资源,不会与共享表的同名方法、属性发生冲突。\n- 线程共享表的成员操作符虽然也能读写共享资源,但要避免覆盖同名的共享表方法与属性。\n- 获取共享数组长度应当用线程共享表对象的 len 函数而不是 # 操作符。 thread.table() = 创建多线程共享表,返回对象可作为参数传入其他线程函数。\n可选使用参数 @1 指定线程共享变量名,\n省略参数 @1 则自动分配线程共享变量名。\n\nthread.var 以及 thread.table 分配的线程共享变量名上限为\n:0x3FFFFFFFFFFFFC0000000000000 个。\n应及时调用线程共享表的 release 函数释放对象与空闲的共享变量名\n\n可选用参数 @2 指定是否要重新初始化并创建新的共享表。\n如果未指定共享表名称,则总是重新初始化共享表\n!thread_table. thread.table.array() = 创建多线程共享数组,返回对象可作为参数传入其他线程函数。\n可选使用参数 @1 指定线程共享变量名,\n省略参数 @1 则自动分配线程共享变量名。\n\nthread.var 以及 thread.table 分配的线程共享变量名上限为\n:0x3FFFFFFFFFFFFC0000000000000 个。\n应及时调用线程共享表的 release 函数释放对象与空闲的共享变量名\n\n可选用参数 @2 指定是否要重新初始化并创建新的共享表。\n如果未指定共享表名称,则总是重新初始化共享表\n!thread_table. !thread_table.? = 使用索引下标 [] 可读写共享表全部键值。\n使用成员属性操作符 . 则先访问对象的函数成员。\n\n不要拿普通表直接覆盖线程共享表本身,应存为共享表里的成员表。\n\n因为每次读取共享表的成员都会在当前线程复制一个新的副本。\n所以要修改线程共享表里面的子表,必须先读取到当前线程的本地变量。 !thread_table.name = 共享表名字,不要改动 !thread_table.length = 数组返回数组长度,表不含数组成员且不是数组类型时返回 null。\n可使用 thread.table.array 创建数组类型的线程共享表。\n\n# 操作符仅用于计算表对象自身存储的数组成员,\n但线程共享仅仅是共享表的代理表,并不存储真正的共享数据。 !thread_table.get((.(key) = 读取线程共享表的指定键值。\n参数 @key 指定键,必须遵守线程传参规则。 !thread_table.set(.(key,value) = 设置线程共享表的指定键值。\n参数 @key 指定键,参数 @value 指定值,所有参数都必须遵守线程传参规则。 !thread_table.getByPath( = 按指定的`表路径`查找深层嵌套成员的值。\n找不到`表路径`的任何部分返回 null 而非报错。。\n此函数会内部调用 table.get 实现。 !thread_table.getByPath(.(path) = 根据参数 @path 指定的`表路径`在线程共享表内查找值。\n\n参数 @path 使用与 table.get,table.set 相同的语法:\n- 使用成员操作符 `.` 分隔上下级路径。\n- 使用下标 `[]` 包含的表达式表示元素的键,空`[]`(仅限 `path` 参数内)表示数组最后一个元素。\n- 上述路径可以任意组合,嵌套路径从左到右逐层深入。\n找不到指定路径中的任何部分时返回 null,不会报错,也不会创建指定路径的对路。 !thread_table.setByPath( = 按指定的`表路径`设置深层嵌套成员的值。\n`表路径`中不存在的父级路径会自动添加新的表对象。\n此函数会内部调用 table.set 实现。 !thread_table.setByPath(.(path,value) = @在参线程共享表内对参数 @path 指定`表路径`的成员赋值。\n\n参数 @path 使用与 table.get,table.set 相同的语法:\n- 使用成员操作符 `.` 分隔上下级路径。\n- 使用下标 `[]` 包含的表达式表示元素的键,空`[]`(仅限 `path` 参数内)表示在数组尾部增加新对象。\n- 上述路径可以任意组合,嵌套路径从左到右逐层深入,遇到不存在的父级路径会自动创建表对象。 !thread_table.lenByPath(.(path) = 根据参数 @path 指定的`表路径`在线程共享表内查找成员并返回其数组长度。\n路径语法请参考 table.get 函数说明。 !thread_table.next(.() = 获取table的第一个键值对元素 !thread_table.next(.( key ) = 迭代获取table的下一个键值对元素 !thread_table.tostring(__) = 返回调用 table.tostring 序列化线程共享表数据获得的字符串。 !thread_table.concat(.(arg1->->->) = 拼接多个 table 对象,参数用法请与 table.concat 相同 !thread_table.insert(.(要插入的值,要插入的位置 ) = 插入元素到指定位置,参数用法请与 table.insert 相同 !thread_table.insert(.(要插入的值 ) = 插入元素到 table 头部,参数用法请与 table.insert 相同 !thread_table.remove(.(位置) = 在表中指定位置移除元素,参数用法请与 table.insert 相同 !thread_table.remove(.( ) = 在 table 头部移除元素,参数用法请与 table.insert 相同 !thread_table.push(.(__) = 在顺序数组尾部压入一个或多个元素,返回数组大小。\n参数用法请与 table.push 相同 !thread_table.push(.(__v1,v2,v3,...) = 在顺序数组尾部压入多个元素,返回数组大小。\n参数用法请与 table.push 相同 !thread_table.pop(__) = 在顺序数组尾部弹出一个或多个元素并作为返回值。\n参数用法请与 table.pop 相同 !thread_table.sort(.() = 排序。\n参数用法请与 table.sort 相同 !thread_table.sort(.( comProc) = 排序,comProc 指定用于比较元素大小的函数(必须是纯函数、在共享线程内执行)。\n参数用法请与 table.sort 相同 !thread_table.reverse(__) = table 数组倒序排列。 !thread_table.range(__) = 返回table数组的最小索引,最大索引。\n例如 `var min,max=tab.range()` !thread_table.unpack(__) = 返回表中所有的元素。\n例如 `a,b,c,d,e = tab.unpack()` !thread_table.left(len__) = 返回 table 对象左侧开始返回指定个数的元素。\n参数用法请与 table.left 相同 !thread_table.right(len__ = 返回 table 对象右侧开始返回指定个数的元素。\n参数用法请与 table.right 相同 !thread_table.len() = 返回 table 对象的数组元素长度,不含数组成员则返回 0。\nlength 属性也可以返回数组长度,但表不是数组类型时返回 null。\n\n# 操作符仅用于计算表对象自身存储的数组成员,\n但线程共享仅仅是共享表的代理表,并不存储真正的共享数据。 !thread_table.count() = 获取 table 成员总数 !thread_table.unshift(.(要插入的一个或多个元素) = 插入一个或多个元素到数组头部,返回数组长度。\n参数用法请与 table.unshift 相同 !thread_table.shift(.(移除数目) = 自数组头部移除并返回指定个数成员,参数 @1 默认为 1 。\n此函数用法请与 table.shift 相同。 !thread_table.append(__) = 追加一个或多个数组到线程共享表,\n此函数内部使用table.append实现,规则相同,\n但无返回值 !thread_table.add(.(字段名,数值) = 修改共享表中参数 @1 指定名字的字段值。\n旧的字段值必须为 null 或数值。\n如果旧值为 null 则直接赋值为参数@2。\n如果旧值为数值则增加参数 @2 指定的数值。 !thread_table.each = @for k,v in ??.each() { __/*遍历表对象,k 为当前键,v 为当前值*/ } !thread_table.splice(.(位置,删除长度,要插入的一个或多个元素) = 在线程共享表指定位置删除指定长度元素,替换为不定个数的插入元素。\n如果删除了元素,该函数返回包含删除元素的数组 !thread_table.slice(.(开始位置,结束位置) = 从指定位置截取并返回新数组,\n开始位置可选,默认为1\n结束位置可选,默认为数组长度,返回值包含结束位置元素,\n如果位置参数为负数,则自右侧反向计算 !thread_table.assign( = 覆盖式混入表,\n支持覆盖已存在的值,不支持递归混入成员表,\n此函数不复制元表。\n\n与 table.assign 不同的是线程共享表的 assign 方法不会返回任何值。 !thread_table.assign(.(任意多个混入对象->->->) = 参数 @1 为空则创建新表。\n使用后面的对象混入前面的对象(浅拷贝),并返回该对象\n该函数仅修改第一个参数(混入目标) ,覆盖已存在的键值\n此函数不会覆盖已存在的只读成员\n\n遇到任何参数为 null 则停止合并返回。 !thread_table.clear() = 清空共享表中的所有值 !thread_table.release() = 释放线程共享表,释放后不应当再使用 end intellisense**/