• R/O
  • SSH

YSLib: Commit

The YSLib project - main repository


Commit MetaInfo

Revision63856ce04e5eda2e8bb05b73126939919b58ce95 (tree)
Zeit2022-05-08 23:20:20
AutorFrankHB <frankhb1989@gmai...>
CommiterFrankHB

Log Message

更新主分支版本: build 944 rev 10 。

Ändern Zusammenfassung

Diff

diff -r 5575c569a1e8 -r 63856ce04e5e YBase/include/ystdex/cassert.h
--- a/YBase/include/ystdex/cassert.h Tue Apr 26 01:57:13 2022 +0800
+++ b/YBase/include/ystdex/cassert.h Sun May 08 22:20:20 2022 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2012-2016, 2018-2021 FrankHB.
2+ © 2012-2016, 2018-2022 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file cassert.h
1212 \ingroup YStandardEx
1313 \brief ISO C 断言/调试跟踪扩展。
14-\version r309
14+\version r311
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 432
1717 \par 创建时间:
1818 2013-07-27 04:11:53 +0800
1919 \par 修改时间:
20- 2021-12-13 12:37 +0800
20+ 2022-04-30 21:53 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -150,7 +150,7 @@
150150 // NOTE: As %assert, this may be undefined and redefined.
151151 #ifndef YAssertNonnull
152152 //! \since build 495
153-# define YAssertNonnull(_expr) YAssert(bool(_expr), "Null reference found.")
153+# define YAssertNonnull(_expr) YAssert(_expr, "Null reference found.")
154154 #endif
155155
156156 #ifndef YTrace
diff -r 5575c569a1e8 -r 63856ce04e5e YBase/include/ystdex/container.hpp
--- a/YBase/include/ystdex/container.hpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YBase/include/ystdex/container.hpp Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file container.hpp
1212 \ingroup YStandardEx
1313 \brief 通用容器操作。
14-\version r2610
14+\version r2611
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 338
1717 \par 创建时间:
1818 2012-09-12 01:36:20 +0800
1919 \par 修改时间:
20- 2022-04-05 07:04 +0800
20+ 2022-05-05 02:34 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -202,7 +202,7 @@
202202 const_iterator position;
203203
204204 prefix_eraser(container_type& con) ynothrow
205- : prefix_eraser(con, con.end())
205+ : prefix_eraser(con, con.begin())
206206 {}
207207 //! \pre 第二参数是第一参数的迭代器。
208208 prefix_eraser(container_type& con, const_iterator i)
diff -r 5575c569a1e8 -r 63856ce04e5e YBase/include/ystdex/function.hpp
--- a/YBase/include/ystdex/function.hpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YBase/include/ystdex/function.hpp Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file function.hpp
1212 \ingroup YStandardEx
1313 \brief 函数基本操作和调用包装对象。
14-\version r5052
14+\version r5053
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 847
1717 \par 创建时间:
1818 2018-12-13 01:24:06 +0800
1919 \par 修改时间:
20- 2022-03-21 12:08 +0800
20+ 2022-04-29 00:50 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -377,7 +377,7 @@
377377 static _tRet
378378 call(const _tContent& content, const _fInvoke& f, _tParams&&... args)
379379 {
380- yconstraint(bool(content));
380+ yconstraint(bool(content.has_value()));
381381 yassume(f);
382382 return f(content, yforward(args)...);
383383 }
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/include/NPL/NPLA.h
--- a/YFramework/include/NPL/NPLA.h Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/include/NPL/NPLA.h Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA.h
1212 \ingroup NPL
1313 \brief NPLA 公共接口。
14-\version r9455
14+\version r9468
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 663
1717 \par 创建时间:
1818 2016-01-07 10:32:34 +0800
1919 \par 修改时间:
20- 2022-04-22 19:31 +0800
20+ 2022-05-08 16:16 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -613,6 +613,7 @@
613613 /*!
614614 \brief 标记记号节点:递归变换节点,转换其中的词素为记号值。
615615 \note 先变换子节点。
616+\warning 不保证嵌套调用安全。
616617 \since build 753
617618 */
618619 YF_API void
@@ -1602,10 +1603,15 @@
16021603 /*!
16031604 \brief 对每个子项提升项的值数据成员可能包含的引用值。
16041605 \sa LiftToReturn
1605-\since build 830
16061606 */
1607+//@{
1608+//! \since build 944
1609+inline PDefH(void, LiftSubtermsToReturn, TermNode::Container& con)
1610+ ImplExpr(std::for_each(con.begin(), con.end(), LiftToReturn))
1611+//! \since build 830
16071612 inline PDefH(void, LiftSubtermsToReturn, TermNode& term)
1608- ImplExpr(std::for_each(term.begin(), term.end(), LiftToReturn))
1613+ ImplExpr(LiftSubtermsToReturn(term.GetContainerRef()))
1614+//@}
16091615
16101616 //! \pre 断言:参数指定的项是枝节点。
16111617 //@{
@@ -1947,7 +1953,9 @@
19471953 \brief 名称解析结果。
19481954 \since build 821
19491955
1950- 名称解析的返回结果是环境中的绑定目标的对象指针和直接保存绑定目标的环境的引用。
1956+ 名称解析结果可以是:
1957+ 环境中的绑定目标的非空对象指针和直接保存绑定目标的环境的引用;
1958+ 表示没有找到指定变量的空指针和未指定的环境引用的值。
19511959 */
19521960 using NameResolution
19531961 = pair<observer_ptr<BindingMap::mapped_type>, shared_ptr<Environment>>;
@@ -2699,7 +2707,7 @@
26992707 若重定向可能具有共享所有权的失败,则表示资源访问错误,如构成循环引用;
27002708 发现环境的循环引用视为失败,抛出异常;其它情形行为未定义。
27012709 以上支持的宿主值类型被依次尝试访问。若成功,则使用此宿主值类型访问环境。
2702- 对列表,使用 DFS (深度优先搜索)依次递归检查其元素。
2710+ 对列表,使用 DFS(深度优先搜索)依次递归检查其元素。
27032711 循环重定向不终止。
27042712 */
27052713 YB_ATTR_nodiscard static Environment::NameResolution
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/include/NPL/NPLA1.h
--- a/YFramework/include/NPL/NPLA1.h Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/include/NPL/NPLA1.h Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.h
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r9447
14+\version r9448
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 472
1717 \par 创建时间:
1818 2014-02-02 17:58:24 +0800
1919 \par 修改时间:
20- 2022-04-26 00:10 +0800
20+ 2022-05-02 05:35 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -677,7 +677,7 @@
677677 \since build 896
678678 */
679679 inline PDefH(ReductionStatus, ReduceReturnUnspecified, TermNode& term) ynothrow
680- ImplRet(term.SetValue(ValueToken::Unspecified), ReductionStatus::Clean)
680+ ImplRet(term.Value = ValueToken::Unspecified, ReductionStatus::Clean)
681681
682682
683683 /*!
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/include/NPL/SContext.h
--- a/YFramework/include/NPL/SContext.h Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/include/NPL/SContext.h Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file SContext.h
1212 \ingroup NPL
1313 \brief S 表达式上下文。
14-\version r4186
14+\version r4233
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 304
1717 \par 创建时间:
1818 2012-08-03 19:55:41 +0800
1919 \par 修改时间:
20- 2022-03-18 03:12 +0800
20+ 2022-04-28 03:46 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -29,8 +29,9 @@
2929 #define NPL_INC_SContext_h_ 1
3030
3131 #include "YModules.h"
32-#include YFM_NPL_Lexical // for ystdex::copy_and_swap, pmr, ByteParser,
33-// ystdex::expand_proxy, ystdex::unref, ystdex::as_const, LexemeList;
32+#include YFM_NPL_Lexical // for ystdex::copy_and_swap, std::swap, pmr,
33+// ByteParser, ystdex::expand_proxy, ystdex::unref, ystdex::as_const,
34+// LexemeList;
3435 #include YFM_YSLib_Core_ValueNode // for YSLib::Deref, YSLib::MakeIndex,
3536 // YSLib::NoContainer, YSLib::NoContainerTag, YSLib::ValueNode,
3637 // YSLib::ValueObject, YSLib::forward_as_tuple, YSLib::get,
@@ -43,6 +44,7 @@
4344 // YSLib::AccessPtr, ystdex::head_of_t, ystdex::addrof, ystdex::compose, pair,
4445 // std::is_lvalue_reference, YSLib::Alert, YSLib::stack;
4546 #include YFM_YSLib_Core_YException // for YSLib::LoggedEvent;
47+#include <ystdex/operators.hpp> // for ystdex::equality_comparable;
4648 #include <ystdex/deref_op.hpp> // for ystdex::call_value_or;
4749 #include <ystdex/range.hpp> // for std::iterator_traits,
4850 // ystdex::range_iterator_t, ystdex::begin, ystdex::end,
@@ -213,7 +215,7 @@
213215 类似 ValueNode 的节点类型,但没有名称数据成员、按键比较和按键访问,
214216 且使用 list 而不是 ystdex::mapped_set 作为容器。
215217 */
216-class YF_API TermNode
218+class YF_API TermNode : private ystdex::equality_comparable<TermNode>
217219 {
218220 private:
219221 // TODO: Deduplicate within %ValueNode?
@@ -254,12 +256,15 @@
254256 : container(a)
255257 {}
256258 TermNode(const Container& con)
257- : container(con)
259+ : TermNode(con, con.get_allocator())
258260 {}
259261 TermNode(Container&& con)
260262 : container(std::move(con))
261263 {}
262- //! \since build 853
264+ /*!
265+ \note 除非 Value 的构造非嵌套调用安全,支持构造任意子节点时的嵌套调用安全。
266+ \since build 853
267+ */
263268 //@{
264269 template<typename... _tParams,
265270 yimpl(typename = enable_value_constructible_t<_tParams...>)>
@@ -270,7 +275,8 @@
270275 template<typename... _tParams,
271276 yimpl(typename = enable_value_constructible_t<_tParams...>)>
272277 TermNode(const Container& con, _tParams&&... args)
273- : container(con), Value(yforward(args)...)
278+ : TermNode(std::allocator_arg, con.get_allocator(), con,
279+ yforward(args)...)
274280 {}
275281 template<typename... _tParams,
276282 yimpl(typename = enable_value_constructible_t<_tParams...>)>
@@ -289,7 +295,7 @@
289295 inline
290296 TermNode(std::allocator_arg_t, allocator_type a, const Container& con,
291297 _tParams&&... args)
292- : container(con, a), Value(yforward(args)...)
298+ : container(ConSub(con, a)), Value(yforward(args)...)
293299 {}
294300 template<typename... _tParams,
295301 yimpl(typename = enable_value_constructible_t<_tParams...>)>
@@ -299,11 +305,11 @@
299305 : container(std::move(con), a), Value(yforward(args)...)
300306 {}
301307 //@}
302- //! \warning 非嵌套调用安全。
308+ //! \warning 不保证嵌套调用安全。
303309 TermNode(const ValueNode& nd, allocator_type a)
304310 : container(ConCons(nd.GetContainer(), a)), Value(nd.Value)
305311 {}
306- //! \warning 非嵌套调用安全。
312+ //! \warning 不保证嵌套调用安全。
307313 TermNode(ValueNode&& nd, allocator_type a)
308314 : container(ConCons(std::move(nd.GetContainerRef()), a)),
309315 Value(std::move(nd.Value))
@@ -324,17 +330,19 @@
324330 std::initializer_list<TermNode> il, _tParams&&... args)
325331 : TermNode(std::allocator_arg, a, Container(il, a), yforward(args)...)
326332 {}
327- //! \warning 非嵌套调用安全。
333+ //! \warning 不保证嵌套调用安全。
328334 explicit
329335 TermNode(const ValueNode& nd)
330336 : container(ConCons(nd.GetContainer())), Value(nd.Value)
331337 {}
332- //! \warning 非嵌套调用安全。
338+ //! \warning 不保证嵌套调用安全。
333339 explicit
334340 TermNode(ValueNode&& nd)
335341 : container(ConCons(std::move(nd.GetContainer()))),
336342 Value(std::move(nd.Value))
337343 {}
344+ //! \note 除非 Value 的构造非嵌套调用安全,支持构造任意子节点时的嵌套调用安全。
345+ //@{
338346 /*!
339347 \brief 复制构造:使用参数和参数的分配器。
340348 \since build 879
@@ -344,13 +352,14 @@
344352 {}
345353 //! \brief 复制构造:使用参数和参数指定的分配器。
346354 TermNode(const TermNode& nd, allocator_type a)
347- : container(nd.container, a), Value(nd.Value), Tags(nd.Tags)
355+ : container(ConSub(nd.container, a)), Value(nd.Value), Tags(nd.Tags)
348356 {}
349357 DefDeMoveCtor(TermNode)
350358 TermNode(TermNode&& nd, allocator_type a)
351359 : container(std::move(nd.container), a), Value(std::move(nd.Value)),
352360 Tags(nd.Tags)
353361 {}
362+ //@}
354363
355364 /*!
356365 \brief 复制赋值:使用参数副本和交换操作。
@@ -365,7 +374,7 @@
365374 DefDeMoveAssignment(TermNode)
366375 /*
367376 \brief 析构:类定义外默认实现。
368- \note 支持移除任意子节点时的嵌套调用安全。
377+ \note 除非 Value 的析构非嵌套调用安全,支持移除任意子节点时的嵌套调用安全。
369378 \since build 916
370379 */
371380 ~TermNode()
@@ -380,6 +389,16 @@
380389 Clear();
381390 }
382391
392+ /*!
393+ \brief 比较相等。
394+ \warning 不保证嵌套调用安全。
395+ \since build 944
396+ */
397+ YB_ATTR_nodiscard YB_PURE friend
398+ PDefHOp(bool, ==, const TermNode& x, const TermNode& y) ynothrow
399+ ImplRet(x.Tags == y.Tags && x.GetContainer() == y.GetContainer()
400+ && x.Value == y.Value)
401+
383402 //! \since build 853
384403 YB_PURE DefBoolNeg(YB_PURE explicit, bool(Value) || !empty())
385404
@@ -456,6 +475,8 @@
456475 con.emplace(position, NoContainer, yforward(args)...);
457476 }
458477
478+ //! \note 除非 Value 的析构非嵌套调用安全,支持移除任意子节点时的嵌套调用安全。
479+ //@{
459480 //! \note 不访问 Tags 。
460481 PDefH(void, Clear, ) ynothrow
461482 // XXX: The order can be siginificant.
@@ -464,10 +485,10 @@
464485 /*!
465486 \brief 清除容器。
466487 \post 断言:\c IsLeaf(*this) 。
467- \note 支持移除任意子节点时的嵌套调用安全。
468488 */
469489 void
470490 ClearContainer() ynothrow;
491+ //@}
471492
472493 /*!
473494 \note 允许被参数中被复制的对象直接或间接地被目标引用。
@@ -485,18 +506,22 @@
485506 //@}
486507
487508 private:
488- //! \warning 非嵌套调用安全。
509+ //! \warning 不保证嵌套调用安全。
489510 //@{
490- static TermNode::Container
511+ YB_ATTR_nodiscard YB_PURE static TermNode::Container
491512 ConCons(const ValueNode::Container&);
492- static TermNode::Container
513+ YB_ATTR_nodiscard YB_PURE static TermNode::Container
493514 ConCons(ValueNode::Container&&);
494- static TermNode::Container
515+ YB_ATTR_nodiscard YB_PURE static TermNode::Container
495516 ConCons(const ValueNode::Container&, allocator_type);
496- static TermNode::Container
517+ YB_ATTR_nodiscard YB_PURE static TermNode::Container
497518 ConCons(ValueNode::Container&&, allocator_type);
498519 //@}
499520
521+ //! \since build 934
522+ YB_ATTR_nodiscard YB_PURE static Container
523+ ConSub(const Container&, allocator_type);
524+
500525 public:
501526 template<class _tCon, typename _fCallable,
502527 yimpl(typename = ystdex::enable_if_t<
@@ -588,7 +613,8 @@
588613 "Invalid allocator found."), container.swap(nd.container))
589614
590615 PDefH(void, SwapContent, TermNode& term) ynothrowv
591- ImplExpr(SwapContainer(term), swap(Value, term.Value))
616+ ImplExpr(SwapContainer(term), swap(Value, term.Value),
617+ std::swap(Tags, term.Tags))
592618
593619 YB_ATTR_nodiscard YB_PURE PDefH(iterator, begin, ) ynothrow
594620 ImplRet(container.begin())
@@ -638,7 +664,7 @@
638664 ImplRet(container.size())
639665
640666 friend PDefH(void, swap, TermNode& x, TermNode& y) ynothrowv
641- ImplExpr(x.SwapContent(y), std::swap(x.Tags, y.Tags))
667+ ImplExpr(x.SwapContent(y))
642668 };
643669
644670 //! \relates TermNode
@@ -871,7 +897,7 @@
871897 /*!
872898 \brief 根据节点和节点容器创建操作设置目标节点的值或子节点。
873899 \note 可用于创建副本。
874-\warning 不检查嵌套深度,不支持嵌套调用安全。
900+\warning 不保证嵌套调用安全。
875901 */
876902 template<typename _fCallable, class _tNode>
877903 void
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/Helper/ShellHelper.cpp
--- a/YFramework/source/Helper/ShellHelper.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/Helper/ShellHelper.cpp Sun May 08 22:20:20 2022 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2010-2015, 2019-2021 FrankHB.
2+ © 2010-2015, 2019-2022 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file ShellHelper.cpp
1212 \ingroup Helper
1313 \brief Shell 助手模块。
14-\version r633
14+\version r636
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 278
1717 \par 创建时间:
1818 2010-04-04 13:42:15 +0800
1919 \par 修改时间:
20- 2021-12-13 01:21 +0800
20+ 2022-04-30 21:53 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -73,7 +73,7 @@
7373 snftime(char* buf, size_t n, const std::tm& tm,
7474 const char* format = DefaultTimeFormat)
7575 {
76- // FIXME: correct behavior for time with BC date(i.e. tm_year < -1900);
76+ // FIXME: Correct behavior for time with BC date(i.e. tm_year < -1900).
7777 std::snprintf(buf, n, format, tm.tm_year + 1900,
7878 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
7979 }
@@ -165,7 +165,7 @@
165165 auto p_list(make_shared<TextList::ListType>(styles.cbegin()
166166 | ystdex::get_key, styles.cend() | ystdex::get_key));
167167
168- YAssert(bool(p_list) && !p_list->empty(),
168+ YAssert(p_list && !p_list->empty(),
169169 "Invalid style mapping state found");
170170 p_list->front() = std::move(default_name);
171171 return make_shared<TextList::ListType>(p_list->cbegin(), p_list->cend());
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/NPL/NPLA1.cpp
--- a/YFramework/source/NPL/NPLA1.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/NPL/NPLA1.cpp Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1.cpp
1212 \ingroup NPL
1313 \brief NPLA1 公共接口。
14-\version r22322
14+\version r22367
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 472
1717 \par 创建时间:
1818 2014-02-02 18:02:47 +0800
1919 \par 修改时间:
20- 2022-04-26 00:32 +0800
20+ 2022-05-02 05:35 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -474,19 +474,24 @@
474474 : alloc(a)
475475 {}
476476
477- YB_FLATTEN ReductionStatus
477+ ReductionStatus
478478 operator()(TermNode& term) const
479479 {
480480 #if NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass
481481 YAssert(remained.empty(), "Invalid state found.");
482- Transform(term, remained);
482+ Transform(term);
483+# if NPL_Impl_NPLA1_Enable_ThunkedThreshold == 0
484+ YAssert(!remained.empty(), "Invalid state found.");
485+ // XXX: For some reason, 'while' here is more efficient than 'do' in the
486+ // generated code with x86_64-pc-linux G++ 11.1.0.
487+# endif
483488 while(!remained.empty())
484489 {
485490 const auto term_ref(std::move(remained.top()));
486491
487492 remained.pop();
488493 for(auto& tm : term_ref.get())
489- Transform(tm, remained);
494+ Transform(tm);
490495 }
491496 #else
492497 Transform(term);
@@ -495,25 +500,40 @@
495500 }
496501
497502 private:
503+ YB_FLATTEN void
504+ Transform(TermNode& term
505+# if defined(NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass) \
506+ && NPL_Impl_NPLA1_Enable_ThunkedThreshold != 0
507+ , size_t n = 0
508+# endif
509+ ) const
510+ {
498511 #if NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass
499- //! \since build 882
512+# if NPL_Impl_NPLA1_Enable_ThunkedThreshold != 0
513+ if(++n < NPL_Impl_NPLA1_Enable_ThunkedThreshold)
514+ {
515+ TransformLeaf(term);
516+ for(auto& tm : term)
517+ Transform(tm, n);
518+ return;
519+ }
520+# endif
521+ remained.push(term);
522+ TransformLeaf(term);
523+#else
524+ TransformLeaf(term);
525+ for(auto& tm : term)
526+ Transform(tm);
527+#endif
528+ }
529+
530+ //! \since build 944
500531 void
501- Transform(TermNode& term, TermStack& terms) const
532+ TransformLeaf(TermNode& term) const
502533 {
503- terms.push(term);
504534 SeparatorTransformer::ReplaceChildren(term, pfx, std::ref(filter));
505535 SeparatorTransformer::ReplaceChildren(term, pfx2, std::ref(filter2));
506536 }
507-#else
508- void
509- Transform(TermNode& term) const
510- {
511- SeparatorTransformer::ReplaceChildren(term, pfx, std::ref(filter));
512- SeparatorTransformer::ReplaceChildren(term, pfx2, std::ref(filter2));
513- for(auto& tm : term)
514- Transform(tm);
515- }
516-#endif
517537 };
518538
519539
@@ -702,7 +722,7 @@
702722 {
703723 const auto p(TermToNamePtr(t));
704724
705- YAssert(bool(p), "Invalid parameter tree found.");
725+ YAssert(p, "Invalid parameter tree found.");
706726 f(*p);
707727 }
708728 }
@@ -1614,10 +1634,7 @@
16141634 break;
16151635 case 'i':
16161636 if(id.substr(1) == "nert")
1617- {
1618- term.Value = ValueToken::Unspecified;
1619- return ReductionStatus::Clean;
1620- }
1637+ return ReduceReturnUnspecified(term);
16211638 else if(id.substr(1) == "gnore")
16221639 {
16231640 term.Value = ValueToken::Ignore;
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/NPL/NPLA1Forms.cpp
--- a/YFramework/source/NPL/NPLA1Forms.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/NPL/NPLA1Forms.cpp Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Forms.cpp
1212 \ingroup NPL
1313 \brief NPLA1 语法形式。
14-\version r26599
14+\version r26663
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2014-02-15 11:19:51 +0800
1919 \par 修改时间:
20- 2022-04-26 00:40 +0800
20+ 2022-05-06 01:57 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -34,7 +34,7 @@
3434 // std::placeholders, std::ref, std::bind, ystdex::as_const, IsLeaf,
3535 // ValueObject, ystdex::ref_eq, RelaySwitched, trivial_swap, shared_ptr,
3636 // ContextHandler, YSLib::unordered_map, string, Environment, lref, TokenValue,
37-// any_ops::use_holder, YSLib::in_place_type, YSLib::HolderFromPointer,
37+// any_ops::use_holder, in_place_type, YSLib::HolderFromPointer,
3838 // YSLib::allocate_shared, InvalidReference, BindParameter, MoveFirstSubterm,
3939 // ResolveEnvironment, ShareMoveTerm, BindParameterWellFormed, ystdex::sfmt,
4040 // TermToStringWithReferenceMark, ResolveTerm, LiftOtherOrCopy,
@@ -46,13 +46,14 @@
4646 // NPL::SwitchToFreshEnvironment, TermTags, YSLib::Debug, YSLib::sfmt,
4747 // A1::MakeForm, ystdex::expand_proxy, NPL::AccessRegular, GetLValueTagsOf,
4848 // RegularizeTerm, IsBranchedList, LiftMovedOther, LiftOtherValue,
49-// ThrowValueCategoryError, std::mem_fn, ystdex::bind1,
50-// ThrowListTypeErrorForNonlist, ThrowInvalidSyntaxError,
51-// CheckEnvironmentFormal, type_id, ystdex::update_thunk, IsTyped, BindSymbol,
52-// IsNPLASymbol, ystdex::fast_all_of, ystdex::call_value_or, A1::AsForm,
53-// LiftCollapsed, YSLib::usystem;
49+// ThrowValueCategoryError, std::mem_fn, ThrowListTypeErrorForNonlist,
50+// ThrowInvalidSyntaxError, CheckEnvironmentFormal, type_id,
51+// ystdex::update_thunk, IsTyped, BindSymbol, A1::AsForm, ystdex::bind1,
52+// IsNPLASymbol, ystdex::fast_all_of, ystdex::call_value_or, LiftCollapsed,
53+// YSLib::usystem;
5454 #include "NPLA1Internals.h" // for A1::Internals API;
5555 #include YFM_NPL_SContext // for Session;
56+#include <ystdex/functor.hpp> // for ystdex::id;
5657 #include <ystdex/scope_guard.hpp> // for ystdex::unique_guard, ystdex::dismiss;
5758 #include <ystdex/container.hpp> // for ystdex::prefix_eraser;
5859
@@ -365,7 +366,7 @@
365366 // bound symbol can then be rebound to an ordinary
366367 // (non-sharing object.
367368 env.Bind(k, TermNode(TermNode::Container(t.get_allocator()),
368- ValueObject(any_ops::use_holder, YSLib::in_place_type<
369+ ValueObject(any_ops::use_holder, in_place_type<
369370 YSLib::HolderFromPointer<shared_ptr_t>>,
370371 store[k] = YSLib::allocate_shared<ContextHandler>(
371372 t.get_allocator(), ThrowInvalidCyclicReference))));
@@ -941,17 +942,17 @@
941942 };
942943
943944
944-//! \since build 874
945+//! \since build 944
945946 void
946-MakeValueListOrMove(TermNode& term, TermNode& nd,
947+MakeValueListOrMove(TermNode::Container& con, TermNode& nd,
947948 ResolvedTermReferencePtr p_ref)
948949 {
949950 MakeValueOrMove(p_ref, [&]{
950951 for(const auto& sub : nd)
951- term.Add(sub);
952+ con.push_back(sub);
952953 }, [&]{
953954 // XXX: No cyclic reference check.
954- term.GetContainerRef().splice(term.end(), nd.GetContainerRef());
955+ con.splice(con.end(), nd.GetContainerRef());
955956 });
956957 }
957958
@@ -964,16 +965,22 @@
964965 TermToStringWithReferenceMark(nd, p_ref).c_str()));
965966 }
966967
968+//! \since build 944
969+void
970+ConsItem(TermNode::Container& con, TermNode& y)
971+{
972+ ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref){
973+ if(IsList(nd_y))
974+ MakeValueListOrMove(con, nd_y, p_ref);
975+ else
976+ ThrowConsError(nd_y, p_ref);
977+ }, y);
978+}
967979 //! \since build 859
968980 void
969981 ConsItem(TermNode& term, TermNode& y)
970982 {
971- ResolveTerm([&](TermNode& nd_y, ResolvedTermReferencePtr p_ref){
972- if(IsList(nd_y))
973- MakeValueListOrMove(term, nd_y, p_ref);
974- else
975- ThrowConsError(nd_y, p_ref);
976- }, y);
983+ ConsItem(term.GetContainerRef(), y);
977984 }
978985
979986 //! \since build 912
@@ -1397,7 +1404,9 @@
13971404 // not unique due to 2-pass iterations (e.g. it may be also used in
13981405 // a interleaved call to %BranchRestFwdReferenced with unspecified
13991406 // order to this call).
1400- term.Value = TermReference(PropagateTo(tm.Tags, tags), tm, r_env);
1407+ term.Value = ValueObject(std::allocator_arg, term.get_allocator(),
1408+ in_place_type<TermReference>, PropagateTo(tm.Tags, tags), tm,
1409+ r_env);
14011410 // NOTE: No %TermNode::ClearContainer is here because %term is expected
14021411 // newly created.
14031412 YAssert(IsLeaf(term), "Invalid term found");
@@ -1463,7 +1472,7 @@
14631472
14641473 ++first;
14651474 if(move)
1466- con.splice(con.end(), f(nd), first, last);
1475+ con.splice(con.end(), f(nd.GetContainerRef()), first, last);
14671476 else
14681477 for(; first != last; ++first)
14691478 f2(con.emplace_back(), *first);
@@ -1474,21 +1483,21 @@
14741483 void
14751484 BranchRestFwdReferenced(TermNode& term, TermNode& nd, bool move)
14761485 {
1477- TransactRest(term, nd, move, std::mem_fn(&TermNode::GetContainerRef),
1478- ystdex::bind1(&TermNode::CopyContent, std::placeholders::_2));
1479-}
1480-
1481-//! \since build 918
1482-template<void(&_rLift)(TermNode&), typename _fInsert>
1486+ TransactRest(term, nd, move, ystdex::id<>(),
1487+ std::mem_fn(&TermNode::CopyContent));
1488+}
1489+
1490+//! \since build 944
1491+template<void(&_rLift)(TermNode::Container&), typename _fInsert>
14831492 ReductionStatus
14841493 RestOrVal(TermNode& term, _fInsert insert)
14851494 {
14861495 return CallResolvedUnary([&](TermNode& nd, ResolvedTermReferencePtr p_ref){
14871496 if(IsBranchedList(nd))
14881497 TransactRest(term, nd, NPL::IsMovable(p_ref),
1489- [](TermNode& tm) -> TermNode::Container&{
1490- _rLift(tm);
1491- return tm.GetContainerRef();
1498+ [](TermNode::Container& con) -> TermNode::Container&{
1499+ _rLift(con);
1500+ return con;
14921501 }, [&](TermNode& nterm, TermNode& tm){
14931502 insert(nterm, tm, p_ref->GetTags());
14941503 });
@@ -1529,17 +1538,17 @@
15291538 }, term);
15301539 }
15311540
1532-//! \since build 853
1541+//! \since build 944
15331542 void
1534-LiftNoOp(TermNode&)
1543+LiftNoOp(TermNode::Container&)
15351544 // XXX: See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100472.
15361545 #if !(YB_IMPL_GNUCPP && YB_HAS_NOEXCEPT && __cplusplus >= 201703L)
15371546 ynothrow
15381547 #endif
15391548 {}
15401549
1541-//! \since build 918
1542-template<void(&_rLift)(TermNode&)>
1550+//! \since build 944
1551+template<void(&_rLift)(TermNode::Container&)>
15431552 void
15441553 SetRestImpl(TermNode& term)
15451554 {
@@ -1549,14 +1558,15 @@
15491558 if(IsList(nd_y))
15501559 {
15511560 const auto a(nd_x.get_allocator());
1552- TermNode nd_new(a);
1553-
1554- nd_new.emplace();
1555- MakeValueListOrMove(nd_new, nd_y, p_ref_y);
1556- _rLift(nd_new);
1561+ TermNode::Container con_new(a);
1562+
1563+ con_new.emplace_back();
1564+ MakeValueListOrMove(con_new, nd_y, p_ref_y);
1565+ _rLift(con_new);
15571566 // XXX: The order is significant.
1558- AccessFirstSubterm(nd_new) = MoveFirstSubterm(nd_x);
1559- swap(nd_x, nd_new);
1567+ con_new.front() = MoveFirstSubterm(nd_x);
1568+ swap(nd_x.GetContainerRef(), con_new);
1569+ nd_x.Value.Clear();
15601570 }
15611571 else
15621572 ThrowListTypeErrorForNonlist(nd_y, p_ref_y);
@@ -1832,19 +1842,27 @@
18321842 }
18331843
18341844
1835-//! \since build 859
1845+/*!
1846+\pre 第三参数非空。
1847+\since build 859
1848+*/
18361849 ReductionStatus
18371850 ApplyImpl(TermNode& term, ContextNode& ctx, shared_ptr<Environment> p_env)
18381851 {
1852+ YAssert(p_env, "Invalid environment found.");
1853+
18391854 auto i(term.begin());
18401855 auto& comb(NPL::Deref(++i));
18411856
18421857 ForwardToUnwrapped(comb);
1843-
1844- TermNode expr(std::allocator_arg, term.get_allocator(), {std::move(comb)});
1845-
1846- ConsItem(expr, NPL::Deref(++i));
1847- term = std::move(expr);
1858+ {
1859+ TermNode::Container tcon(term.get_allocator());
1860+
1861+ tcon.push_back(std::move(comb));
1862+ ConsItem(tcon, NPL::Deref(++i));
1863+ tcon.swap(term.GetContainerRef());
1864+ }
1865+ ClearCombiningTags(term);
18481866 // NOTE: The precondition is same to the last call in %EvalImplUnchecked.
18491867 // See also the precondition of %Combine<TailCall>::RelayEnvSwitch.
18501868 return Combine<TailCall>::RelayEnvSwitch(ctx, term, std::move(p_env));
@@ -1907,6 +1925,8 @@
19071925 RemoveTermPostfix(gd);
19081926 }
19091927 term.Value.Clear();
1928+ // XXX: No %ClearCombiningTags is called, as it would be determined later
1929+ // in the subsequent combiner call.
19101930 }
19111931 //@}
19121932
@@ -2364,8 +2384,8 @@
23642384 // to make the list elements having %TermTags::Temporary.
23652385 BranchRestFwdReferenced(nterm, nd, NPL::IsMovable(tags));
23662386 }, [](TermNode& nterm, TermNode& o, TermTags o_tags){
2367- TransactRest(nterm, o, NPL::IsMovable(o.Tags | o_tags), std::mem_fn(
2368- &TermNode::GetContainerRef), std::mem_fn(&TermNode::CopyContent));
2387+ TransactRest(nterm, o, NPL::IsMovable(o.Tags | o_tags), ystdex::id<>(),
2388+ std::mem_fn(&TermNode::CopyContent));
23692389 });
23702390 return ReductionStatus::Retained;
23712391 }
@@ -4485,7 +4505,6 @@
44854505 yunseq(term.GetContainerRef() = std::move(con),
44864506 term.Value = std::move(vo));
44874507 SetupNextTerm(ctx, term);
4488- ClearCombiningTags(term);
44894508 RemoveHead(term);
44904509 return ReductionStatus::Retained;
44914510 },
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/NPL/NPLA1Internals.cpp
--- a/YFramework/source/NPL/NPLA1Internals.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/NPL/NPLA1Internals.cpp Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Internals.cpp
1212 \ingroup NPL
1313 \brief NPLA1 内部接口。
14-\version r20599
14+\version r20602
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 473
1717 \par 创建时间:
1818 2020-02-15 13:20:08 +0800
1919 \par 修改时间:
20- 2022-04-05 15:19 +0800
20+ 2022-04-30 21:54 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 非公开模块名称:
@@ -177,8 +177,6 @@
177177 void
178178 TCOAction::CompressFrameList()
179179 {
180- auto i(RecordList.cbegin());
181-
182180 ystdex::retry_on_cond(ystdex::id<>(), [&]() -> bool{
183181 bool removed = {};
184182
@@ -250,8 +248,7 @@
250248 ReduceAsSubobjectReference(TermNode& term, shared_ptr<TermNode> p_sub,
251249 const EnvironmentReference& r_env)
252250 {
253- YAssert(bool(p_sub),
254- "Invalid subterm to form a subobject reference found.");
251+ YAssert(p_sub, "Invalid subterm to form a subobject reference found.");
255252
256253 // NOTE: Irregular representation is constructed for the subobject
257254 // reference.
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/NPL/NPLA1Internals.h
--- a/YFramework/source/NPL/NPLA1Internals.h Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/NPL/NPLA1Internals.h Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file NPLA1Internals.h
1212 \ingroup NPL
1313 \brief NPLA1 内部接口。
14-\version r22076
14+\version r22108
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 882
1717 \par 创建时间:
1818 2020-02-15 13:20:08 +0800
1919 \par 修改时间:
20- 2022-04-25 01:04 +0800
20+ 2022-05-06 01:22 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 非公开模块名称:
@@ -29,9 +29,9 @@
2929 #define NPL_INC_NPLA1Internals_h_ 1
3030
3131 #include "YModules.h"
32-#include YFM_NPL_NPLA1 // for ContextNode, TermNode, ContextState,
33-// ReductionStatus, Reducer, YSLib::map, lref, Environment,
34-// set, NPL::Deref, IsTyped, EnvironmentList, EnvironmentReference, tuple,
32+#include YFM_NPL_NPLA1 // for shared_ptr, ContextNode, NPL::Deref, NPLException,
33+// TermNode, ReductionStatus, Reducer, YSLib::map, lref, Environment,
34+// set, IsTyped, EnvironmentList, EnvironmentReference, tuple,
3535 // YSLib::get, YSLib::forward_list, size_t, list, std::declval,
3636 // EnvironmentGuard, MoveKeptGuard, A1::NameTypedContextHandler, TermReference,
3737 // ThrowTypeErrorForInvalidType, NPL::TryAccessLeaf, type_id,
@@ -43,6 +43,7 @@
4343 #include <ystdex/ref.hpp> // for std::reference_wrapper, std::ref,
4444 // ystdex::unref;
4545 #include <ystdex/bind.hpp> // for ystdex::bind1, std::placeholders::_2;
46+#include <ystdex/function.hpp> // for ystdex::unchecked_function;
4647 #include <ystdex/function_adaptor.hpp> // for ystdex::update_thunk;
4748 #include <iterator> // for std::next;
4849
@@ -78,6 +79,13 @@
7879 // supporting PTC are noted in implementations separatedly.
7980 #define NPL_Impl_NPLA1_Enable_TCO true
8081 #define NPL_Impl_NPLA1_Enable_Thunked true
82+// NOTE: If non zero, thunks are only used only for more than certain level of
83+// nested calls occur. The value should be small enough to ensure the nested
84+// call safety guarantee still works in practice. Currently only enabled for
85+// thunked separator passes (see below).
86+#ifndef NPL_Impl_NPLA1_Enable_ThunkedThreshold
87+# define NPL_Impl_NPLA1_Enable_ThunkedThreshold yimpl(16U)
88+#endif
8189 #define NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass NPL_Impl_NPLA1_Enable_Thunked
8290
8391 //! \since build 820
@@ -331,7 +339,7 @@
331339 \brief 一次调用检查守卫。
332340 \since build 943
333341 */
334- mutable ystdex::optional<ystdex::guard<OneShotChecker>> one_shot_guard;
342+ mutable ystdex::optional<ystdex::guard<OneShotChecker>> one_shot_guard{};
335343
336344 public:
337345 //! \since build 819
@@ -347,7 +355,7 @@
347355 "Invalid value for combining term found.");
348356 return std::move(term.Value);
349357 // XXX: After the move, %term.Value is unspecified.
350- }()), one_shot_guard()
358+ }())
351359 // XXX: Do not call %AssertValueTags on %term, as it is usually a
352360 // combinitation instead of the representation of some object language
353361 // value.
@@ -359,11 +367,10 @@
359367 // object always live longer than the older one.
360368 : term_guard(std::move(a.term_guard)),
361369 req_lift_result(a.req_lift_result), stashed(ystdex::exchange(a.stashed,
362- ContextHandler())), EnvGuard(std::move(a.EnvGuard)),
363- one_shot_guard()
370+ ContextHandler())), EnvGuard(std::move(a.EnvGuard))
364371 {
365- if(a.one_shot_guard.has_value())
366- one_shot_guard.emplace((*a.one_shot_guard).func);
372+ if(a.one_shot_guard)
373+ one_shot_guard.emplace(a.one_shot_guard->func);
367374 }
368375 DefDeMoveCtor(TCOAction)
369376 // XXX: Out of line destructor here is inefficient.
@@ -456,12 +463,12 @@
456463 YB_ATTR_nodiscard OneShotChecker
457464 MakeOneShotChecker()
458465 {
459- if(!one_shot_guard.has_value())
466+ if(!one_shot_guard)
460467 // XXX: The context is only used to determine the allocator, which
461468 // is an implementation detail. Usually the context in caller
462469 // should be the same, though.
463470 one_shot_guard.emplace(EnvGuard.func.Context.get());
464- return (*one_shot_guard).func;
471+ return one_shot_guard->func;
465472 }
466473
467474 //! \since build 940
@@ -1099,7 +1106,7 @@
10991106
11001107
11011108 //! \since build 881
1102-using Action = function<void()>;
1109+using Action = ystdex::unchecked_function<void()>;
11031110
11041111
11051112 //! \since build 897
@@ -1123,11 +1130,18 @@
11231130 == &ref, "Invalid term or reference value found."), term.SetContent(
11241131 bound.GetContainer(), EnsureLValueReference(TermReference(ref))))
11251132
1126-//! \since build 920
1127-inline PDefH(void, SetEvaluatedValue, TermNode& term,
1128- TermNode& bound, shared_ptr<Environment>& p_env)
1129- ImplExpr(term.Value = TermReference(NPL::Deref(p_env).MakeTermTags(bound)
1130- & ~TermTags::Unique, bound, std::move(p_env)))
1133+/*!
1134+\pre 第三参数非空。
1135+\since build 944
1136+*/
1137+inline PDefH(void, SetEvaluatedValue, TermNode& term, TermNode& bound,
1138+ const shared_ptr<Environment>& p_env)
1139+ ImplExpr(term.Value = [&](Environment& env){
1140+ return ValueObject(std::allocator_arg, term.get_allocator(),
1141+ in_place_type<TermReference>, env.MakeTermTags(bound)
1142+ & ~TermTags::Unique, bound,
1143+ EnvironmentReference(p_env, env.GetAnchorPtr()));
1144+ }(NPL::Deref(p_env)))
11311145
11321146
11331147 //! \since build 917
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/NPL/SContext.cpp
--- a/YFramework/source/NPL/SContext.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/NPL/SContext.cpp Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file SContext.cpp
1212 \ingroup NPL
1313 \brief S 表达式上下文。
14-\version r2120
14+\version r2292
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 329
1717 \par 创建时间:
1818 2012-08-03 19:55:59 +0800
1919 \par 修改时间:
20- 2022-03-14 18:23 +0800
20+ 2022-04-29 18:57 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -26,11 +26,143 @@
2626
2727
2828 #include "NPL/YModules.h"
29-#include YFM_NPL_SContext // for ystdex::ref_eq;
29+#include YFM_NPL_SContext // for vector, NPL::Deref, std::allocator_arg,
30+// YSLib::stack, pair, lref;
31+#include <ystdex/function.hpp> // for ystdex::unchecked_function,
32+// ystdex::trivial_swap;
33+// NOTE: This enables thunked actions in copy for nested call safety, instead of
34+// using stacks.
35+#define NPL_Impl_SContext_Enable_ThunkedActions true
36+#if NPL_Impl_SContext_Enable_ThunkedActions
37+// NOTE: If non zero, thunks are only used only for more than certain level of
38+// nested calls occur. The value should be small enough to ensure the nested
39+// call safety guarantee still works in practice.
40+# ifndef NPL_Impl_SContext_Enable_ThunkedThreshold
41+# define NPL_Impl_SContext_Enable_ThunkedThreshold yimpl(32U)
42+# endif
43+#else
44+# include <ystdex/expanded_function.hpp> // for ystdex::retry_on_cond;
45+#endif
3046
3147 namespace NPL
3248 {
3349
50+#if NPL_Impl_SContext_Enable_ThunkedActions
51+//! \since build 944
52+namespace
53+{
54+
55+struct ConSubThunk final
56+{
57+ // XXX: This is more efficient than %function instance with
58+ // %ystdex::update_thunk for normal cases.
59+ using Action = ystdex::unchecked_function<void()>;
60+ mutable vector<Action> Current;
61+
62+ ConSubThunk(TermNode::allocator_type a) ynothrow
63+ : Current(a)
64+ {}
65+
66+ void
67+ operator()(TermNode::Container& res, const TermNode::Container& con)
68+ const
69+ {
70+ CopySubterms(res, con.begin(), con.end());
71+ while(!Current.empty())
72+ {
73+ const auto f(std::move(Current.back()));
74+
75+ Current.pop_back();
76+ f();
77+ }
78+ }
79+
80+ void
81+ CopySubterms(TermNode::Container& r, TNCIter first, TNCIter last
82+# if NPL_Impl_SContext_Enable_ThunkedThreshold != 0
83+ , size_t n = 0
84+# endif
85+ ) const
86+ {
87+ YAssert(first != last, "Invalid range found.");
88+
89+ auto& dst(r.emplace_back());
90+ const auto& src(NPL::Deref(first));
91+
92+ ++first;
93+# if NPL_Impl_SContext_Enable_ThunkedThreshold != 0
94+ if(++n < NPL_Impl_SContext_Enable_ThunkedThreshold)
95+ {
96+ if(!src.empty())
97+ CopySubterms(dst.GetContainerRef(), src.begin(), src.end(), n);
98+ if(first != last)
99+ CopySubterms(r, first, last, n);
100+ CopyValueAndTags(dst, src);
101+ return;
102+ }
103+# endif
104+ UpdateCopyValueAndTags(dst, src);
105+ if(first != last)
106+ UpdateCopySubterms(r, first, last
107+# if NPL_Impl_SContext_Enable_ThunkedThreshold != 0
108+ , n
109+# endif
110+ );
111+ if(!src.empty())
112+ Update(
113+# if NPL_Impl_SContext_Enable_ThunkedThreshold != 0
114+ [&, n]{
115+ CopySubterms(dst.GetContainerRef(), src.begin(), src.end(), n);
116+# else
117+ [&]{
118+ CopySubterms(dst.GetContainerRef(), src.begin(), src.end());
119+# endif
120+ });
121+ }
122+
123+ static PDefH(void, CopyValueAndTags, TermNode& dst, const TermNode& src)
124+ ImplUnseq(dst.Value = src.Value, dst.Tags = src.Tags)
125+
126+ template<typename _func>
127+ void
128+ Update(_func f) const
129+ {
130+ // XXX: Allocators are not used here for performance.
131+ Current.push_back(std::move(f));
132+ }
133+
134+ void
135+ UpdateCopySubterms(TermNode::Container& r, TNCIter first, TNCIter last
136+# if NPL_Impl_SContext_Enable_ThunkedThreshold != 0
137+ , size_t n = 0
138+# endif
139+ ) const
140+ {
141+ Update(
142+# if NPL_Impl_SContext_Enable_ThunkedThreshold != 0
143+ [&, first, last, n]{
144+ CopySubterms(r, first, last, n);
145+# else
146+ [&, first, last]{
147+ CopySubterms(r, first, last);
148+# endif
149+ });
150+ }
151+
152+ // XXX: Making it a separate definition slightly improves the generated code
153+ // quality with x86_64-pc-linux G++ 11.1.0.
154+ void
155+ UpdateCopyValueAndTags(TermNode& dst, const TermNode& src) const
156+ {
157+ Update([&]{
158+ CopyValueAndTags(dst, src);
159+ });
160+ }
161+};
162+
163+} // unnamed namespace;
164+#endif
165+
34166 void
35167 TermNode::ClearContainer() ynothrow
36168 {
@@ -106,6 +238,65 @@
106238 }
107239
108240
241+TermNode::Container
242+TermNode::ConSub(const Container& con, allocator_type a)
243+{
244+ Container res(a);
245+
246+ if(!con.empty())
247+ {
248+#if NPL_Impl_SContext_Enable_ThunkedActions
249+ // XXX: This works more efficiently when
250+ // %NPL_Impl_SContext_Enable_ThunkedThreshold is sufficient large.
251+ ConSubThunk{a}(res, con);
252+#else
253+ // XXX: Use of the default container (%deque) is more efficient.
254+ YSLib::stack<pair<lref<TermNode>, lref<const TermNode>>> remained(a),
255+ tms(a);
256+
257+ // XXX: The order of copying the %Value objects is preserved. Otherwise
258+ // the resource allocations and tags modifications are consided pure,
259+ // so the order is not necessarily the same in naive implementations
260+ // not supporting the nested call safety.
261+ for(const auto& sub : con)
262+ {
263+ res.emplace_back();
264+ remained.emplace(res.back(), sub),
265+ tms.emplace(res.back(), sub),
266+ res.back().Tags = sub.Tags;
267+ // TODO: Use %not_fn?
268+ ystdex::retry_on_cond([&]() ynothrow{
269+ return !remained.empty();
270+ }, [&]{
271+ auto& dst_con(remained.top().first.get().GetContainerRef());
272+ auto& src(remained.top().second.get());
273+
274+ remained.pop();
275+ for(auto i(src.rbegin()); i != src.rend(); ++i)
276+ {
277+ dst_con.emplace_front();
278+
279+ auto& nterm(dst_con.front());
280+ auto& tm(*i);
281+
282+ remained.emplace(nterm, tm),
283+ tms.emplace(nterm, tm),
284+ nterm.Tags = tm.Tags;
285+ }
286+ });
287+ ystdex::retry_on_cond([&]() ynothrow{
288+ return !tms.empty();
289+ }, [&]{
290+ tms.top().first.get().Value = tms.top().second.get().Value;
291+ tms.pop();
292+ });
293+ }
294+#endif
295+ }
296+ return res;
297+}
298+
299+
109300 void
110301 ReaderState::UpdateLexeme(const string& lexeme)
111302 {
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/YCLib/FileSystem.cpp
--- a/YFramework/source/YCLib/FileSystem.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/YCLib/FileSystem.cpp Sun May 08 22:20:20 2022 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2011-2021 FrankHB.
2+ © 2011-2022 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file FileSystem.cpp
1212 \ingroup YCLib
1313 \brief 平台相关的文件系统接口。
14-\version r4989
14+\version r4991
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 312
1717 \par 创建时间:
1818 2012-05-30 22:41:35 +0800
1919 \par 修改时间:
20- 2021-12-12 16:54 +0800
20+ 2022-04-30 21:54 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -711,7 +711,7 @@
711711 {
712712 if(*this)
713713 {
714- YAssert(bool(GetNativeHandle()), "Invariant violation found.");
714+ YAssert(GetNativeHandle(), "Invariant violation found.");
715715
716716 #if YCL_Win32
717717 const auto res(Deref(static_cast<platform_ex::DirectoryFindData*>(
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/YSLib/Service/ImageProcessing.cpp
--- a/YFramework/source/YSLib/Service/ImageProcessing.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/YSLib/Service/ImageProcessing.cpp Sun May 08 22:20:20 2022 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2014-2015, 2021 FrankHB.
2+ © 2014-2015, 2021-2022 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file ImageProcessing.cpp
1212 \ingroup Service
1313 \brief 图像处理。
14-\version r285
14+\version r287
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 554
1717 \par 创建时间:
1818 2014-11-16 16:37:27 +0800
1919 \par 修改时间:
20- 2021-12-24 23:51 +0800
20+ 2022-04-30 21:54 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -37,7 +37,7 @@
3737 CompactPixmap
3838 Zoom(const HBitmap& bitmap, ImageScale ratio)
3939 {
40- YAssert(bool(bitmap), "Invalid bitmap found.");
40+ YAssert(bitmap, "Invalid bitmap found.");
4141
4242 const Size bmp_size(bitmap.GetSize());
4343
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/YSLib/Service/TextRenderer.cpp
--- a/YFramework/source/YSLib/Service/TextRenderer.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/YSLib/Service/TextRenderer.cpp Sun May 08 22:20:20 2022 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2009-2015, 2017, 2019 FrankHB.
2+ © 2009-2015, 2017, 2019, 2022 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file TextRenderer.cpp
1212 \ingroup Service
1313 \brief 文本渲染。
14-\version r2766
14+\version r2768
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 275
1717 \par 创建时间:
1818 2009-11-13 00:06:05 +0800
1919 \par 修改时间:
20- 2019-01-14 18:54 +0800
20+ 2022-04-30 21:55 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -48,7 +48,7 @@
4848 YB_ATTR_nodiscard PaintContext
4949 ClipChar(const Graphics& g, const Point& pen, const CharBitmap& cbmp, Rect r)
5050 {
51- YAssert(bool(g), "Invalid graphics context found.");
51+ YAssert(g, "Invalid graphics context found.");
5252
5353 const auto pt(ClipBounds(r, Rect(pen.X + cbmp.GetLeft(),
5454 pen.Y - cbmp.GetTop(), cbmp.GetWidth(), cbmp.GetHeight())));
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/YSLib/Service/YBlend.cpp
--- a/YFramework/source/YSLib/Service/YBlend.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/YSLib/Service/YBlend.cpp Sun May 08 22:20:20 2022 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2015 FrankHB.
2+ © 2015, 2022 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file YBlend.cpp
1212 \ingroup Service
1313 \brief 平台无关的图像块操作。
14-\version r56
14+\version r59
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 584
1717 \par 创建时间:
1818 2015-03-17 06:19:55 +0800
1919 \par 修改时间:
20- 2015-03-17 06:45 +0800
20+ 2022-04-30 21:56 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -39,7 +39,7 @@
3939 void
4040 BlendRect(const Graphics& g, const Rect& r, Color c)
4141 {
42- YAssert(bool(g), "Invalid graphics context found.");
42+ YAssert(g, "Invalid graphics context found.");
4343 BlendRectRaw(g.GetBufferPtr(), Pixel(c), g.GetSize(), r);
4444 }
4545
@@ -47,7 +47,7 @@
4747 void
4848 CompositeRect(const Graphics& g, const Rect& r, Color c)
4949 {
50- YAssert(bool(g), "Invalid graphics context found.");
50+ YAssert(g, "Invalid graphics context found.");
5151 CompositeRectRaw(g.GetBufferPtr(), Pixel(c), g.GetSize(), r);
5252 }
5353
diff -r 5575c569a1e8 -r 63856ce04e5e YFramework/source/YSLib/Service/YDraw.cpp
--- a/YFramework/source/YSLib/Service/YDraw.cpp Tue Apr 26 01:57:13 2022 +0800
+++ b/YFramework/source/YSLib/Service/YDraw.cpp Sun May 08 22:20:20 2022 +0800
@@ -1,5 +1,5 @@
11 /*
2- © 2011-2016, 2019 FrankHB.
2+ © 2011-2016, 2019, 2022 FrankHB.
33
44 This file is part of the YSLib project, and may only be used,
55 modified, and distributed under the terms of the YSLib project
@@ -11,13 +11,13 @@
1111 /*! \file YDraw.cpp
1212 \ingroup Service
1313 \brief 平台无关的二维图形光栅化。
14-\version r1118
14+\version r1120
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 219
1717 \par 创建时间:
1818 2011-06-16 19:45:33 +0800
1919 \par 修改时间:
20- 2019-01-14 18:54 +0800
20+ 2022-04-30 21:56 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -149,7 +149,7 @@
149149 void
150150 FillRect(const Graphics& g, const Rect& r, Color c)
151151 {
152- YAssert(bool(g), "Invalid graphics context found.");
152+ YAssert(g, "Invalid graphics context found.");
153153 FillRectRaw(g.GetBufferPtr(), Pixel(c), g.GetSize(), r);
154154 }
155155
diff -r 5575c569a1e8 -r 63856ce04e5e doc/ChangeLog.V0.9.txt
--- a/doc/ChangeLog.V0.9.txt Tue Apr 26 01:57:13 2022 +0800
+++ b/doc/ChangeLog.V0.9.txt Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file ChangeLog.V0.9.txt
1212 \ingroup Documentation
1313 \brief 版本更新历史记录 - V0.9 。
14-\version r9118
14+\version r9260
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since build 800
1717 \par 创建时间:
1818 2020-10-12 17:19:23 +0800
1919 \par 修改时间:
20- 2022-04-26 01:15 +0800
20+ 2022-05-08 21:29 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -32,6 +32,149 @@
3232
3333 $now
3434 (
35+ / %YBase.YStandardEx $=
36+ (
37+ * "ill-formed expression" @ "'yconstraint' operand"
38+ @ "static function %call" @ "class template specialization \
39+ %function_traits for %empty_function_policy::no_check"
40+ @ %YBase.YStandardEx.Function $since b849,
41+ / "constructor#1" @ "class template %prefix_eraser" @ %Container
42+ ^ "first iterator in the range" ~ "last iterator in the range"
43+ // Subsequent insertions would not be guarded by the old behavior. \
44+ And it is also more natural to construct a no-op guard by \
45+ default.
46+ ),
47+ / DLDI "simplified 1st operand" @ "%YAssert invocations" !^ 'bool'
48+ $effective @ %(YBase.YStandardEx.CAssert,
49+ YFramework.(Helper.ShellHelper, NPL.(NPLA1, NPLA1Internals),
50+ YCLib.FileSystem, YSLib.Service.(ImageProcessing, TextRenderer,
51+ YBlend))),
52+ // A few exceptions are in %YFramework.YSLib.Service.YGDI, which need \
53+ casts.
54+ / %YFramework.NPL $=
55+ (
56+ / @ "class %TermNode" @ %Scontext $=
57+ (
58+ (
59+ * "missing swapping tags" @ "function %SetContent#3"
60+ $since b857 ^ "%std::swap";
61+ // Also to be consistent %SetContnet. Now this is same to the \
62+ friend function %swap.
63+ / DLDI "simplified friend function %swap" !^ "%std::swap"
64+ ),
65+ (
66+ + "2 static function %AreEqual";
67+ + "friend function %operator==";
68+ + "friend %operator!="
69+ ^ "private base %ystdex::equality_comparable<TermNode>"
70+ // If a container of list is saved in %Value, it requires '==' of \
71+ %TermNode to work with %ValueObject.
72+ ),
73+ (
74+ / "constructors with parameter of 'const TermNode&'"
75+ ^ "allocator from the 1st argument";
76+ // This is more consistent to the copy constructor.
77+ * $re_add(b916) "missing nested call safety in handling terms from \
78+ object language" @ (("copy constructor with allocator";
79+ $comp "copy constructor"), "constructors with pamameter of \
80+ 'const Container&'") $orig (@ "type %TermNode" $since b674)
81+ $= (/ $impl ^ ("%ystdex::unchecked_function"
82+ @ $dep_from %YBase.YStandardEx.Function))
83+ )
84+ ),
85+ / %NPLA1Internals $=
86+ (
87+ - DLDI "unused variable" @ "member function \
88+ %TCOAction::CompressFrameList",
89+ // Also to eliminate G++ waraning: [-Wunused-variable].
90+ / DLDI "simplified one shot guard initialization"
91+ ^ "brace-initializer '{}'",
92+ / DLDI "simplified" @ ("copy constructor",
93+ "function %MakeOneShotChecker")
94+ ^ ('->' ~ ('*', '.'), "cast" ~ "%optional::has_value"),
95+ / "%Action" ^ "%ystdex::unchecked_function" ~ "%function",
96+ + "macro %NPL_Impl_NPLA1_Enable_ThunkedThreshold",
97+ / "function %SetEvaluatedValue" $=
98+ (
99+ + 'const' @ "3rd parameter",
100+ + DD "'\pre' command" @ "Doxygen comment",
101+ / DLI "optimized for nonnull value"
102+ ^ "explicit %EnvironmentReference construction",
103+ / DLI ^ "allocator"
104+ )
105+ ),
106+ / %NPLA $=
107+ (
108+ + "function %LiftSubtermsToReturn with parameter of \
109+ 'TermNode::Container&'";
110+ / DLDI "simplified %LiftSubtermsToReturn#2"
111+ ),
112+ / %NPLA1 $=
113+ (
114+ / @ "constructors %REPLContext" $=
115+ (
116+ + DLDI "assertion" @ "default %Preprocess",
117+ / DLI "improved nested calls efficiency"
118+ ^ $dep_from ("%NPL_Impl_NPLA1_Enable_ThunkedThreshold"
119+ @ %NPLA1Internals)
120+ ),
121+ / DLDI "simplified function %DefaultEvaluateLeaf"
122+ ^ "%ReduceReturnUnspecified",
123+ / DLDI "simplified function %ReduceReturnUnspecified"
124+ !^ "%TermNode::SetValue",
125+ // To be consistent with other uses. This is also a bit \
126+ tighter in generated code.
127+ (
128+ + "enumerator %Pair" @ "enum class %ValueToken";
129+ + "%ValueToken::Pair support" @ "%to_string"
130+ )
131+ ),
132+ / @ "namespace %Forms" @ %NPLA1Forms $=
133+ (
134+ / @ "function %Apply" $=
135+ (
136+ + DLDI "internal assertion",
137+ * $re_ex(b913) "move-only object not allowed in terms handled \
138+ by functions as native implemention of applicatives"
139+ @ ("function %Apply" $since b859)
140+ $= (/ $re_ex(b914) "avoided unexpected copy by list \
141+ initialization via %std::initializer_list instance"
142+ @ "%TermNode construction")
143+ ),
144+ / DLDI "accessed rest list value by container" @ "functions \
145+ %(LetAsterisk, LetAsteriskRef, RestFwd, RestVal, SetRest, \
146+ SetRestRef)" $dep_from ("%LiftSubtermsToReturn" @ %NPLA),
147+ - $revert(b943) DLI "redundant %ClearCombiningTags call"
148+ @ "function %Call1CC",
149+ * "missing preserving tags" @ "modified lists" @ "functions \
150+ %(SetRest, SetRestRef)" $orig (@ %NPLA1 $since b857),
151+ * $comp DLI "missing clearing the container before the calls \
152+ of the applicative" @ "functions %(AccL, AccR)" $since b942
153+ $dep_from %YBase.YStadardEx.Container,
154+ // This would not be exposed when the 1st subterm of the \
155+ combining term is regular. However, it is unreliable.
156+ / DLDI "all %YSLib::in_place_type" -> "%in_place_type",
157+ // The using declaration is already in NPLA.h.
158+ / DLI "setting reference result" @ "%(ListExtractFirst, \
159+ LetAsterisk, LetAsteriskRef)" ^ "allocator"
160+ ),
161+ / %Dependency $=
162+ (
163+ * $comp "unexpected copy of initializers on calls"
164+ @ "native implementation" @ "applicative %apply" $since b859
165+ $dep_from ("%Apply" @ %NPLA1Forms)
166+ * $comp "missing preserving reference property" @ "modified lists"
167+ @ "applicatives ('set-rest!', 'set-rest%!')"
168+ $dep_from ("functions %(SetRest, SetRestRef)" @ %NPLA1Forms)
169+ $since b857
170+ // The applicatives were introduced in b834, but the \
171+ %TermTags::Temporary was used since b857.
172+ )
173+ )
174+),
175+
176+b943
177+(
35178 / %Tools $=
36179 (
37180 / %Scripts $=
diff -r 5575c569a1e8 -r 63856ce04e5e doc/Definitions.txt
--- a/doc/Definitions.txt Tue Apr 26 01:57:13 2022 +0800
+++ b/doc/Definitions.txt Sun May 08 22:20:20 2022 +0800
@@ -11,13 +11,13 @@
1111 /*! \file Definitions.txt
1212 \ingroup Documentation
1313 \brief 方法和公共域定义与说明。
14-\version r14440
14+\version r14455
1515 \author FrankHB <frankhb1989@gmail.com>
1616 \since 早于 build 132
1717 \par 创建时间:
1818 2010-01-26 19:34:51 +0800
1919 \par 修改时间:
20- 2022-04-22 19:28 +0800
20+ 2022-04-30 02:36 +0800
2121 \par 文本编码:
2222 UTF-8
2323 \par 模块名称:
@@ -524,6 +524,11 @@
524524
525525 $dir NPL
526526 {
527+$unit SContext
528+{
529+NPL_Impl_SContext_Enable_ThunkedActions
530+#NPL_Impl_SContext_Enable_ThunkedThreshold
531+}
527532 $unit NPLA
528533 {
529534 #NPL_NPLA_CheckEnvironmentReferenceCount
@@ -535,19 +540,24 @@
535540 {
536541 NPL_NPLA_EnsureInPlaceNativeNumbers
537542 #NPL_Impl_NPLAMath_UseQuadMath
538-#NPL_Impl_NPLAMath_Has_UInt128
539-}
540-$unit NPLA1Forms
541-{
542-NPL_NPLA1Forms_CheckContinuationFrames
543+#NPL_Impl_NPLAMath_has_uint128
543544 }
544545 $internal $unit NPLA1Internals
545546 {
546547 NPL_Impl_NPLA1_Enable_InlineDirect
547548 NPL_Impl_NPLA1_Enable_TCO
548549 NPL_Impl_NPLA1_Enable_Thunked
550+#NPL_Impl_NPLA1_Enable_ThunkedThreshold
549551 NPL_Impl_NPLA1_Enable_ThunkedSeparatorPass
550552 }
553+$unit NPLA1
554+{
555+NPL_Impl_NPLA1_AssertParameterMatch
556+}
557+$unit NPLA1Forms
558+{
559+NPL_NPLA1Forms_CheckContinuationFrames
560+}
551561 $unit Dependency
552562 {
553563 NPL_Impl_NPLA1_Native_Forms
Show on old repository browser