zeolite-lang 0.16.1.0 → 0.17.0.0
raw patch · 84 files changed
+5116/−2800 lines, 84 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- CompilerCxx.LanguageModule: [lmExternal] :: LanguageModule c -> [CategoryName]
- Types.Builtin: isPrimitiveType :: ValueType -> Bool
- Types.Procedure: isLiteralCategory :: CategoryName -> Bool
+ CompilerCxx.Code: expressionFromLiteral :: PrimitiveType -> String -> (ExpressionType, ExpressionValue)
+ CompilerCxx.Code: isStoredUnboxed :: ValueType -> Bool
+ CompilerCxx.Naming: templateIncludes :: [String]
+ Types.TypeInstance: BuiltinCharBuffer :: CategoryName
- CompilerCxx.LanguageModule: LanguageModule :: Set Namespace -> Set Namespace -> Set Namespace -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [CategoryName] -> [CategoryName] -> ExprMap c -> LanguageModule c
+ CompilerCxx.LanguageModule: LanguageModule :: Set Namespace -> Set Namespace -> Set Namespace -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [AnyCategory c] -> [CategoryName] -> ExprMap c -> LanguageModule c
Files
- ChangeLog.md +51/−0
- base/.zeolite-module +14/−10
- base/Category_Bool.cpp +0/−231
- base/Category_Char.cpp +0/−257
- base/Category_Float.cpp +0/−243
- base/Category_Int.cpp +0/−257
- base/Category_String.cpp +0/−354
- base/builtin.0rp +41/−0
- base/category-source.cpp +0/−292
- base/category-source.hpp +2/−77
- base/function.hpp +5/−5
- base/internal.hpp +151/−0
- base/logging.cpp +0/−234
- base/pooled.hpp +109/−0
- base/src/Extension_Bool.cpp +102/−0
- base/src/Extension_Char.cpp +114/−0
- base/src/Extension_CharBuffer.cpp +110/−0
- base/src/Extension_Float.cpp +111/−0
- base/src/Extension_Int.cpp +118/−0
- base/src/Extension_String.cpp +204/−0
- base/src/category-source.cpp +297/−0
- base/src/logging.cpp +234/−0
- base/src/thread-crosser.cc +33/−0
- base/src/types.cpp +259/−0
- base/thread-crosser.cc +0/−33
- base/types.cpp +0/−87
- base/types.hpp +71/−16
- example/parser/parse-text.0rp +4/−8
- example/parser/parser.0rp +14/−17
- example/parser/test-data.0rp +2/−4
- example/primes/flag.0rx +8/−4
- lib/container/auto-tree.0rp +141/−0
- lib/container/auto-tree.0rx +350/−0
- lib/container/helpers.0rp +88/−0
- lib/container/helpers.0rt +107/−0
- lib/container/helpers.0rx +45/−0
- lib/container/interfaces.0rp +23/−0
- lib/container/search-tree.0rp +1/−19
- lib/container/search-tree.0rt +6/−4
- lib/container/search-tree.0rx +78/−388
- lib/container/sorting.0rp +53/−0
- lib/container/sorting.0rt +154/−0
- lib/container/sorting.0rx +104/−0
- lib/container/src/Extension_Vector.cpp +0/−8
- lib/container/tree-set.0rp +59/−0
- lib/container/tree-set.0rt +172/−0
- lib/container/tree-set.0rx +92/−0
- lib/container/validated-tree.0rp +34/−0
- lib/math/.zeolite-module +2/−0
- lib/math/categorical-tree.0rp +72/−0
- lib/math/categorical-tree.0rt +164/−0
- lib/math/categorical-tree.0rx +231/−0
- lib/math/math.0rt +135/−0
- lib/math/tests.0rt +0/−135
- lib/math/validated-tree.0rp +36/−0
- lib/thread/condition.0rp +2/−4
- lib/thread/thread.0rp +4/−2
- lib/util/counters.0rp +21/−1
- lib/util/counters.0rt +47/−0
- lib/util/counters.0rx +40/−10
- lib/util/helpers.0rp +141/−0
- lib/util/helpers.0rt +139/−0
- lib/util/helpers.0rx +122/−0
- lib/util/iterator.0rp +0/−11
- lib/util/mutex.0rp +11/−0
- src/Cli/Compiler.hs +6/−10
- src/Cli/RunCompiler.hs +6/−2
- src/Cli/TestRunner.hs +10/−7
- src/Compilation/ProcedureContext.hs +4/−1
- src/Compilation/ScopeContext.hs +2/−1
- src/CompilerCxx/CategoryContext.hs +2/−2
- src/CompilerCxx/Code.hs +23/−0
- src/CompilerCxx/CxxFiles.hs +13/−12
- src/CompilerCxx/LanguageModule.hs +5/−11
- src/CompilerCxx/Naming.hs +5/−1
- src/CompilerCxx/Procedure.hs +8/−8
- src/Parser/TypeInstance.hs +7/−6
- src/Types/Builtin.hs +2/−11
- src/Types/Procedure.hs +4/−10
- src/Types/TypeInstance.hs +2/−0
- tests/builtin-types.0rt +169/−4
- tests/function-calls.0rt +115/−0
- tests/regressions.0rt +1/−0
- zeolite-lang.cabal +4/−3
ChangeLog.md view
@@ -1,5 +1,55 @@ # Revision history for zeolite-lang +## 0.17.0.0 -- 2021-04-06++### Language++* **[breaking]** Adds `CharBuffer`, as a random-access, mutable `Char` buffer,+ and makes `WriteAt` a built-in type. (This is breaking because `CharBuffer`+ and `WriteAt` are now reserved.)++* **[fix]** Fixes `reduce<String,Container>`, which previously failed.++* **[fix]** Fixes a race condition in function dispatching that was thought to+ be fixed previously.++* **[behavior]** Improves the memory efficiency of function calls that use 4 or+ fewer arguments, returns, or function params by reusing memory previously+ allocated for function calls.++### Libraries++* **[new]** Additions to `lib/util`:++ * **[new]** Adds `Ranges`, for simple min/max determinations.++ * **[new]** Adds `revZeroIndexed` to `Counter`, to create a reversed sequence+ of zero-indexed container indices.++ * **[new]** Adds `Reversed`, `BySize`, and `AlwaysEqual` comparators, to+ modify `LessThan` and `Equals` behaviors for objects.++ * **[new]** Adds `OrderH` and `ReadAtH`, to extend `LessThan` and `Equals`+ comparisons to simple containers.++* **[new]** Additions to `lib/container`:++ * **[new]** Adds `Sorting`, to support sorting of random-access containers.++ * **[new]** Adds `TreeSet`, to manage set membership of any sortable type.++ * **[new]** Adds `AutoBinaryTree`, to provide binary search tree (BST)+ functionality to custom containers that need to augment each node with+ additional data.++ * **[new]** Implements `Container.size()` in `SearchTree`.++ * **[new]** Adds `KeyValueH`, to extend `LessThan` and `Equals` comparisons to+ `KeyValue`.++* **[new]** Adds `CategoricalTree` to `lib/math`, as a dynamic representation+ of a [categorical distribution][categorical] over objects of any sortable type.+ ## 0.16.1.0 -- 2021-04-02 ### Language@@ -764,6 +814,7 @@ * First version. Released on an unsuspecting world. +[categorical]: https://en.wikipedia.org/wiki/Categorical_distribution [megaparsec]: https://hackage.haskell.org/package/megaparsec [microlens]: https://hackage.haskell.org/package/microlens [microlens-th]: https://hackage.haskell.org/package/microlens-th
base/.zeolite-module view
@@ -2,36 +2,40 @@ path: "base" extra_files: [ category_source {- source: "base/Category_Bool.cpp"+ source: "base/src/Extension_Bool.cpp" categories: [Bool] } category_source {- source: "base/Category_Char.cpp"+ source: "base/src/Extension_Char.cpp" categories: [Char] } category_source {- source: "base/Category_Float.cpp"+ source: "base/src/Extension_CharBuffer.cpp"+ categories: [CharBuffer]+ }+ category_source {+ source: "base/src/Extension_Float.cpp" categories: [Float] } category_source {- source: "base/Category_Int.cpp"+ source: "base/src/Extension_Int.cpp" categories: [Int] } category_source {- source: "base/Category_String.cpp"+ source: "base/src/Extension_String.cpp" categories: [String] } "base/category-header.hpp"- "base/category-source.cpp" "base/category-source.hpp" "base/cycle-check.hpp" "base/function.hpp"- "base/logging.cpp" "base/logging.hpp"- "base/types.cpp"- "base/types.hpp" "base/thread-capture.h" "base/thread-crosser.h"- "base/thread-crosser.cc"+ "base/types.hpp"+ "base/src/category-source.cpp"+ "base/src/logging.cpp"+ "base/src/thread-crosser.cc"+ "base/src/types.cpp" ] mode: incremental {}
− base/Category_Bool.cpp
@@ -1,231 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "Category_Bool.hpp"--#include <map>-#include <sstream>--#include "category-source.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsInt.hpp"-#include "Category_AsFloat.hpp"-#include "Category_Formatted.hpp"-#include "Category_Default.hpp"-#include "Category_Equals.hpp"---#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE-namespace {-const int collection_Bool = 0;-} // namespace-const void* const Functions_Bool = &collection_Bool;-namespace {-class Category_Bool;-class Type_Bool;-class Value_Bool;-struct Category_Bool : public TypeCategory {- std::string CategoryName() const final { return "Bool"; }- Category_Bool() {- CycleCheck<Category_Bool>::Check();- CycleCheck<Category_Bool> marker(*this);- TRACE_FUNCTION("Bool (init @category)")- }- ReturnTuple Dispatch(const CategoryFunction& label, const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Category_Bool::*)(const ParamTuple&, const ValueTuple&);- return TypeCategory::Dispatch(label, params, args);- }-};-Category_Bool& CreateCategory_Bool() {- static auto& category = *new Category_Bool();- return category;-}-struct Type_Bool : public TypeInstance {- std::string CategoryName() const final { return parent.CategoryName(); }- void BuildTypeName(std::ostream& output) const final {- return TypeInstance::TypeNameFrom(output, parent);- }- Category_Bool& parent;- bool CanConvertFrom(const S<const TypeInstance>& from) const final {- std::vector<S<const TypeInstance>> args;- if (!from->TypeArgsForParent(parent, args)) return false;- if(args.size() != 0) {- FAIL() << "Wrong number of args (" << args.size() << ") for " << CategoryName();- }- return true;- }- void Params_Bool(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- using CallType = void(Type_Bool::*)(std::vector<S<const TypeInstance>>&)const;- static DispatchSingle<CallType> all_calls[] = {- DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Bool::Params_AsBool),- DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Bool::Params_AsFloat),- DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Bool::Params_AsInt),- DispatchSingle<CallType>(&GetCategory_Bool(), &Type_Bool::Params_Bool),- DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Bool::Params_Formatted),- DispatchSingle<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchSingle<CallType>* const call = DispatchSelect(table_lock, &category, all_calls);- if (call) {- (this->*call->value)(args);- return true;- }- return false;- }- Type_Bool(Category_Bool& p, Params<0>::Type params) : parent(p) {- CycleCheck<Type_Bool>::Check();- CycleCheck<Type_Bool> marker(*this);- TRACE_FUNCTION("Bool (init @type)")- }- ReturnTuple Dispatch(const S<TypeInstance>& self, const TypeFunction& label,- const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Type_Bool::*)(const ParamTuple&, const ValueTuple&);- static const CallType Table_Default[] = {- &Type_Bool::Call_default,- };- static const CallType Table_Equals[] = {- &Type_Bool::Call_equals,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_Default, Table_Default),- DispatchTable<CallType>(Functions_Equals, Table_Equals),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(params, args);- }- }- return TypeInstance::Dispatch(self, label, params, args);- }- ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_equals(const ParamTuple& params, const ValueTuple& args);-};-S<Type_Bool> CreateType_Bool(Params<0>::Type params) {- static const auto cached = S_get(new Type_Bool(CreateCategory_Bool(), Params<0>::Type()));- return cached;-}-struct Value_Bool : public TypeValue {- Value_Bool(S<Type_Bool> p, bool value) : parent(p), value_(value) {}- ReturnTuple Dispatch(const S<TypeValue>& self, const ValueFunction& label, const ParamTuple& params,const ValueTuple& args) final {- using CallType = ReturnTuple(Value_Bool::*)(const S<TypeValue>&, const ParamTuple&, const ValueTuple&);- static const CallType Table_AsBool[] = {- &Value_Bool::Call_asBool,- };- static const CallType Table_AsFloat[] = {- &Value_Bool::Call_asFloat,- };- static const CallType Table_AsInt[] = {- &Value_Bool::Call_asInt,- };- static const CallType Table_Formatted[] = {- &Value_Bool::Call_formatted,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_AsBool, Table_AsBool),- DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),- DispatchTable<CallType>(Functions_AsInt, Table_AsInt),- DispatchTable<CallType>(Functions_Formatted, Table_Formatted),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(self, params, args);- }- }- return TypeValue::Dispatch(self, label, params, args);- }- std::string CategoryName() const final { return parent->CategoryName(); }- bool AsBool() const final { return value_; }- ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- const S<Type_Bool> parent;- const bool value_;-};--ReturnTuple Type_Bool::Call_default(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Bool.default")- return ReturnTuple(Box_Bool(false));-}-ReturnTuple Type_Bool::Call_equals(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Bool.equals")- const bool Var_arg1 = (args.At(0))->AsBool();- const bool Var_arg2 = (args.At(1))->AsBool();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));-}-ReturnTuple Value_Bool::Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Bool.asBool")- return ReturnTuple(Var_self);-}-ReturnTuple Value_Bool::Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Bool.asFloat")- return ReturnTuple(Box_Float(value_ ? 1.0 : 0.0));-}-ReturnTuple Value_Bool::Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Bool.asInt")- return ReturnTuple(Box_Int(value_? 1 : 0));-}-ReturnTuple Value_Bool::Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Bool.formatted")- return ReturnTuple(Box_String(value_? "true" : "false"));-}-const S<TypeValue>& Var_true = *new S<TypeValue>(new Value_Bool(CreateType_Bool(Params<0>::Type()), true));-const S<TypeValue>& Var_false = *new S<TypeValue>(new Value_Bool(CreateType_Bool(Params<0>::Type()), false));-} // namespace-TypeCategory& GetCategory_Bool() {- return CreateCategory_Bool();-}-S<TypeInstance> GetType_Bool(Params<0>::Type params) {- return CreateType_Bool(params);-}-#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE---S<TypeValue> Box_Bool(bool value) {- return value? Var_true : Var_false;-}
− base/Category_Char.cpp
@@ -1,257 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "Category_Char.hpp"--#include <map>-#include <sstream>--#include "category-source.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsChar.hpp"-#include "Category_AsInt.hpp"-#include "Category_AsFloat.hpp"-#include "Category_Formatted.hpp"-#include "Category_Default.hpp"-#include "Category_Equals.hpp"-#include "Category_LessThan.hpp"---#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE-namespace {-const int collection_Char = 0;-} // namespace-const void* const Functions_Char = &collection_Char;-namespace {-class Category_Char;-class Type_Char;-class Value_Char;-struct Category_Char : public TypeCategory {- std::string CategoryName() const final { return "Char"; }- Category_Char() {- CycleCheck<Category_Char>::Check();- CycleCheck<Category_Char> marker(*this);- TRACE_FUNCTION("Char (init @category)")- }- ReturnTuple Dispatch(const CategoryFunction& label, const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Category_Char::*)(const ParamTuple&, const ValueTuple&);- return TypeCategory::Dispatch(label, params, args);- }-};-Category_Char& CreateCategory_Char() {- static auto& category = *new Category_Char();- return category;-}-struct Type_Char : public TypeInstance {- std::string CategoryName() const final { return parent.CategoryName(); }- void BuildTypeName(std::ostream& output) const final {- return TypeInstance::TypeNameFrom(output, parent);- }- Category_Char& parent;- bool CanConvertFrom(const S<const TypeInstance>& from) const final {- std::vector<S<const TypeInstance>> args;- if (!from->TypeArgsForParent(parent, args)) return false;- if(args.size() != 0) {- FAIL() << "Wrong number of args (" << args.size() << ") for " << CategoryName();- }- return true;- }- void Params_Char(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsChar(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- using CallType = void(Type_Char::*)(std::vector<S<const TypeInstance>>&)const;- static DispatchSingle<CallType> all_calls[] = {- DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Char::Params_AsBool),- DispatchSingle<CallType>(&GetCategory_AsChar(), &Type_Char::Params_AsChar),- DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Char::Params_AsFloat),- DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Char::Params_AsInt),- DispatchSingle<CallType>(&GetCategory_Char(), &Type_Char::Params_Char),- DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Char::Params_Formatted),- DispatchSingle<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchSingle<CallType>* const call = DispatchSelect(table_lock, &category, all_calls);- if (call) {- (this->*call->value)(args);- return true;- }- return false;- }- Type_Char(Category_Char& p, Params<0>::Type params) : parent(p) {- CycleCheck<Type_Char>::Check();- CycleCheck<Type_Char> marker(*this);- TRACE_FUNCTION("Char (init @type)")- }- ReturnTuple Dispatch(const S<TypeInstance>& self, const TypeFunction& label,- const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Type_Char::*)(const ParamTuple&, const ValueTuple&);- static const CallType Table_Default[] = {- &Type_Char::Call_default,- };- static const CallType Table_Equals[] = {- &Type_Char::Call_equals,- };- static const CallType Table_LessThan[] = {- &Type_Char::Call_lessThan,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_Default, Table_Default),- DispatchTable<CallType>(Functions_Equals, Table_Equals),- DispatchTable<CallType>(Functions_LessThan, Table_LessThan),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(params, args);- }- }- return TypeInstance::Dispatch(self, label, params, args);- }- ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_equals(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_lessThan(const ParamTuple& params, const ValueTuple& args);-};-S<Type_Char> CreateType_Char(Params<0>::Type params) {- static const auto cached = S_get(new Type_Char(CreateCategory_Char(), Params<0>::Type()));- return cached;-}-struct Value_Char : public TypeValue {- Value_Char(S<Type_Char> p, PrimChar value) : parent(p), value_(value) {}- ReturnTuple Dispatch(const S<TypeValue>& self, const ValueFunction& label, const ParamTuple& params,const ValueTuple& args) final {- using CallType = ReturnTuple(Value_Char::*)(const S<TypeValue>&, const ParamTuple&, const ValueTuple&);- static const CallType Table_AsBool[] = {- &Value_Char::Call_asBool,- };- static const CallType Table_AsChar[] = {- &Value_Char::Call_asChar,- };- static const CallType Table_AsFloat[] = {- &Value_Char::Call_asFloat,- };- static const CallType Table_AsInt[] = {- &Value_Char::Call_asInt,- };- static const CallType Table_Formatted[] = {- &Value_Char::Call_formatted,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_AsBool, Table_AsBool),- DispatchTable<CallType>(Functions_AsChar, Table_AsChar),- DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),- DispatchTable<CallType>(Functions_AsInt, Table_AsInt),- DispatchTable<CallType>(Functions_Formatted, Table_Formatted),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(self, params, args);- }- }- return TypeValue::Dispatch(self, label, params, args);- }- std::string CategoryName() const final { return parent->CategoryName(); }- PrimChar AsChar() const final { return value_; }- ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asChar(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- const S<Type_Char> parent;- const PrimChar value_;-};--ReturnTuple Type_Char::Call_default(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.default")- return ReturnTuple(Box_Char('\0'));-}-ReturnTuple Type_Char::Call_equals(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.equals")- const PrimChar Var_arg1 = (args.At(0))->AsChar();- const PrimChar Var_arg2 = (args.At(1))->AsChar();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));-}-ReturnTuple Type_Char::Call_lessThan(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.lessThan")- const PrimChar Var_arg1 = (args.At(0))->AsChar();- const PrimChar Var_arg2 = (args.At(1))->AsChar();- return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));-}-ReturnTuple Value_Char::Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.asBool")- return ReturnTuple(Box_Bool(value_ != '\0'));-}-ReturnTuple Value_Char::Call_asChar(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.asChar")- return ReturnTuple(Var_self);-}-ReturnTuple Value_Char::Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.asFloat")- return ReturnTuple(Box_Float(value_));-}-ReturnTuple Value_Char::Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.asInt")- return ReturnTuple(Box_Int(value_));-}-ReturnTuple Value_Char::Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Char.formatted")- std::ostringstream output;- output << value_;- return ReturnTuple(Box_String(output.str()));-}-} // namespace-TypeCategory& GetCategory_Char() {- return CreateCategory_Char();-}-S<TypeInstance> GetType_Char(Params<0>::Type params) {- return CreateType_Char(params);-}-#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE---S<TypeValue> Box_Char(PrimChar value) {- return S_get(new Value_Char(CreateType_Char(Params<0>::Type()), value));-}
− base/Category_Float.cpp
@@ -1,243 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "Category_Float.hpp"--#include <map>-#include <sstream>--#include "category-source.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsInt.hpp"-#include "Category_AsFloat.hpp"-#include "Category_Formatted.hpp"-#include "Category_Default.hpp"-#include "Category_Equals.hpp"-#include "Category_LessThan.hpp"---#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE-namespace {-const int collection_Float = 0;-} // namespace-const void* const Functions_Float = &collection_Float;-namespace {-class Category_Float;-class Type_Float;-class Value_Float;-struct Category_Float : public TypeCategory {- std::string CategoryName() const final { return "Float"; }- Category_Float() {- CycleCheck<Category_Float>::Check();- CycleCheck<Category_Float> marker(*this);- TRACE_FUNCTION("Float (init @category)")- }- ReturnTuple Dispatch(const CategoryFunction& label, const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Category_Float::*)(const ParamTuple&, const ValueTuple&);- return TypeCategory::Dispatch(label, params, args);- }-};-Category_Float& CreateCategory_Float() {- static auto& category = *new Category_Float();- return category;-}-struct Type_Float : public TypeInstance {- std::string CategoryName() const final { return parent.CategoryName(); }- void BuildTypeName(std::ostream& output) const final {- return TypeInstance::TypeNameFrom(output, parent);- }- Category_Float& parent;- bool CanConvertFrom(const S<const TypeInstance>& from) const final {- std::vector<S<const TypeInstance>> args;- if (!from->TypeArgsForParent(parent, args)) return false;- if(args.size() != 0) {- FAIL() << "Wrong number of args (" << args.size() << ") for " << CategoryName();- }- return true;- }- void Params_Float(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- using CallType = void(Type_Float::*)(std::vector<S<const TypeInstance>>&)const;- static DispatchSingle<CallType> all_calls[] = {- DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Float::Params_AsBool),- DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Float::Params_AsFloat),- DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Float::Params_AsInt),- DispatchSingle<CallType>(&GetCategory_Float(), &Type_Float::Params_Float),- DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Float::Params_Formatted),- DispatchSingle<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchSingle<CallType>* const call = DispatchSelect(table_lock, &category, all_calls);- if (call) {- (this->*call->value)(args);- return true;- }- return false;- }- Type_Float(Category_Float& p, Params<0>::Type params) : parent(p) {- CycleCheck<Type_Float>::Check();- CycleCheck<Type_Float> marker(*this);- TRACE_FUNCTION("Float (init @type)")- }- ReturnTuple Dispatch(const S<TypeInstance>& self, const TypeFunction& label,- const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Type_Float::*)(const ParamTuple&, const ValueTuple&);- static const CallType Table_Default[] = {- &Type_Float::Call_default,- };- static const CallType Table_Equals[] = {- &Type_Float::Call_equals,- };- static const CallType Table_LessThan[] = {- &Type_Float::Call_lessThan,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_Default, Table_Default),- DispatchTable<CallType>(Functions_Equals, Table_Equals),- DispatchTable<CallType>(Functions_LessThan, Table_LessThan),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(params, args);- }- }- return TypeInstance::Dispatch(self, label, params, args);- }- ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_equals(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_lessThan(const ParamTuple& params, const ValueTuple& args);-};-S<Type_Float> CreateType_Float(Params<0>::Type params) {- static const auto cached = S_get(new Type_Float(CreateCategory_Float(), Params<0>::Type()));- return cached;-}-struct Value_Float : public TypeValue {- Value_Float(S<Type_Float> p, PrimFloat value) : parent(p), value_(value) {}- ReturnTuple Dispatch(const S<TypeValue>& self, const ValueFunction& label, const ParamTuple& params,const ValueTuple& args) final {- using CallType = ReturnTuple(Value_Float::*)(const S<TypeValue>&, const ParamTuple&, const ValueTuple&);- static const CallType Table_AsBool[] = {- &Value_Float::Call_asBool,- };- static const CallType Table_AsFloat[] = {- &Value_Float::Call_asFloat,- };- static const CallType Table_AsInt[] = {- &Value_Float::Call_asInt,- };- static const CallType Table_Formatted[] = {- &Value_Float::Call_formatted,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_AsBool, Table_AsBool),- DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),- DispatchTable<CallType>(Functions_AsInt, Table_AsInt),- DispatchTable<CallType>(Functions_Formatted, Table_Formatted),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(self, params, args);- }- }- return TypeValue::Dispatch(self, label, params, args);- }- std::string CategoryName() const final { return parent->CategoryName(); }- PrimFloat AsFloat() const final { return value_; }- ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- const S<Type_Float> parent;- const PrimFloat value_;-};--ReturnTuple Type_Float::Call_default(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Float.default")- return ReturnTuple(Box_Float(0.0));-}-ReturnTuple Type_Float::Call_equals(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Float.equals")- const PrimFloat Var_arg1 = (args.At(0))->AsFloat();- const PrimFloat Var_arg2 = (args.At(1))->AsFloat();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));-}-ReturnTuple Type_Float::Call_lessThan(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Float.lessThan")- const PrimFloat Var_arg1 = (args.At(0))->AsFloat();- const PrimFloat Var_arg2 = (args.At(1))->AsFloat();- return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));-}-ReturnTuple Value_Float::Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Float.asBool")- return ReturnTuple(Box_Bool(value_ != 0.0));-}-ReturnTuple Value_Float::Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Float.asFloat")- return ReturnTuple(Var_self);-}-ReturnTuple Value_Float::Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Float.asInt")- return ReturnTuple(Box_Int(value_));-}-ReturnTuple Value_Float::Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Float.formatted")- std::ostringstream output;- output << value_;- return ReturnTuple(Box_String(output.str()));-}-} // namespace-TypeCategory& GetCategory_Float() {- return CreateCategory_Float();-}-S<TypeInstance> GetType_Float(Params<0>::Type params) {- return CreateType_Float(params);-}-#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE---S<TypeValue> Box_Float(PrimFloat value) {- return S_get(new Value_Float(CreateType_Float(Params<0>::Type()), value));-}
− base/Category_Int.cpp
@@ -1,257 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "Category_Int.hpp"--#include <map>-#include <sstream>--#include "category-source.hpp"-#include "Category_AsBool.hpp"-#include "Category_AsChar.hpp"-#include "Category_AsInt.hpp"-#include "Category_AsFloat.hpp"-#include "Category_Formatted.hpp"-#include "Category_Default.hpp"-#include "Category_Equals.hpp"-#include "Category_LessThan.hpp"---#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE-namespace {-const int collection_Int = 0;-} // namespace-const void* const Functions_Int = &collection_Int;-namespace {-class Category_Int;-class Type_Int;-class Value_Int;-struct Category_Int : public TypeCategory {- std::string CategoryName() const final { return "Int"; }- Category_Int() {- CycleCheck<Category_Int>::Check();- CycleCheck<Category_Int> marker(*this);- TRACE_FUNCTION("Int (init @category)")- }- ReturnTuple Dispatch(const CategoryFunction& label, const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Category_Int::*)(const ParamTuple&, const ValueTuple&);- return TypeCategory::Dispatch(label, params, args);- }-};-Category_Int& CreateCategory_Int() {- static auto& category = *new Category_Int();- return category;-}-struct Type_Int : public TypeInstance {- std::string CategoryName() const final { return parent.CategoryName(); }- void BuildTypeName(std::ostream& output) const final {- return TypeInstance::TypeNameFrom(output, parent);- }- Category_Int& parent;- bool CanConvertFrom(const S<const TypeInstance>& from) const final {- std::vector<S<const TypeInstance>> args;- if (!from->TypeArgsForParent(parent, args)) return false;- if(args.size() != 0) {- FAIL() << "Wrong number of args (" << args.size() << ") for " << CategoryName();- }- return true;- }- void Params_Int(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsChar(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsInt(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsFloat(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- using CallType = void(Type_Int::*)(std::vector<S<const TypeInstance>>&)const;- static DispatchSingle<CallType> all_calls[] = {- DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_Int::Params_AsBool),- DispatchSingle<CallType>(&GetCategory_AsChar(), &Type_Int::Params_AsChar),- DispatchSingle<CallType>(&GetCategory_AsFloat(), &Type_Int::Params_AsFloat),- DispatchSingle<CallType>(&GetCategory_AsInt(), &Type_Int::Params_AsInt),- DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_Int::Params_Formatted),- DispatchSingle<CallType>(&GetCategory_Int(), &Type_Int::Params_Int),- DispatchSingle<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchSingle<CallType>* const call = DispatchSelect(table_lock, &category, all_calls);- if (call) {- (this->*call->value)(args);- return true;- }- return false;- }- Type_Int(Category_Int& p, Params<0>::Type params) : parent(p) {- CycleCheck<Type_Int>::Check();- CycleCheck<Type_Int> marker(*this);- TRACE_FUNCTION("Int (init @type)")- }- ReturnTuple Dispatch(const S<TypeInstance>& self, const TypeFunction& label,- const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Type_Int::*)(const ParamTuple&, const ValueTuple&);- static const CallType Table_Default[] = {- &Type_Int::Call_default,- };- static const CallType Table_Equals[] = {- &Type_Int::Call_equals,- };- static const CallType Table_LessThan[] = {- &Type_Int::Call_lessThan,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_Default, Table_Default),- DispatchTable<CallType>(Functions_Equals, Table_Equals),- DispatchTable<CallType>(Functions_LessThan, Table_LessThan),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(params, args);- }- }- return TypeInstance::Dispatch(self, label, params, args);- }- ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_equals(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_lessThan(const ParamTuple& params, const ValueTuple& args);-};-S<Type_Int> CreateType_Int(Params<0>::Type params) {- static const auto cached = S_get(new Type_Int(CreateCategory_Int(), Params<0>::Type()));- return cached;-}-struct Value_Int : public TypeValue {- Value_Int(S<Type_Int> p, PrimInt value) : parent(p), value_(value) {}- ReturnTuple Dispatch(const S<TypeValue>& self, const ValueFunction& label, const ParamTuple& params,const ValueTuple& args) final {- using CallType = ReturnTuple(Value_Int::*)(const S<TypeValue>&, const ParamTuple&, const ValueTuple&);- static const CallType Table_AsBool[] = {- &Value_Int::Call_asBool,- };- static const CallType Table_AsChar[] = {- &Value_Int::Call_asChar,- };- static const CallType Table_AsFloat[] = {- &Value_Int::Call_asFloat,- };- static const CallType Table_AsInt[] = {- &Value_Int::Call_asInt,- };- static const CallType Table_Formatted[] = {- &Value_Int::Call_formatted,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_AsBool, Table_AsBool),- DispatchTable<CallType>(Functions_AsChar, Table_AsChar),- DispatchTable<CallType>(Functions_AsFloat, Table_AsFloat),- DispatchTable<CallType>(Functions_AsInt, Table_AsInt),- DispatchTable<CallType>(Functions_Formatted, Table_Formatted),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(self, params, args);- }- }- return TypeValue::Dispatch(self, label, params, args);- }- std::string CategoryName() const final { return parent->CategoryName(); }- PrimInt AsInt() const final { return value_; }- ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asChar(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- const S<Type_Int> parent;- const PrimInt value_;-};--ReturnTuple Type_Int::Call_default(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.default")- return ReturnTuple(Box_Int(0));-}-ReturnTuple Type_Int::Call_equals(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.equals")- const PrimInt Var_arg1 = (args.At(0))->AsInt();- const PrimInt Var_arg2 = (args.At(1))->AsInt();- return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));-}-ReturnTuple Type_Int::Call_lessThan(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.lessThan")- const PrimInt Var_arg1 = (args.At(0))->AsInt();- const PrimInt Var_arg2 = (args.At(1))->AsInt();- return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));-}-ReturnTuple Value_Int::Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.asBool")- return ReturnTuple(Box_Bool(value_ != 0));-}-ReturnTuple Value_Int::Call_asChar(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.asChar")- return ReturnTuple(Box_Char(value_ % 0xff));-}-ReturnTuple Value_Int::Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.asFloat")- return ReturnTuple(Box_Float(value_));-}-ReturnTuple Value_Int::Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.asInt")- return ReturnTuple(Var_self);-}-ReturnTuple Value_Int::Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("Int.formatted")- std::ostringstream output;- output << value_;- return ReturnTuple(Box_String(output.str()));-}-} // namespace-TypeCategory& GetCategory_Int() {- return CreateCategory_Int();-}-S<TypeInstance> GetType_Int(Params<0>::Type params) {- return CreateType_Int(params);-}-#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE---S<TypeValue> Box_Int(PrimInt value) {- return S_get(new Value_Int(CreateType_Int(Params<0>::Type()), value));-}
− base/Category_String.cpp
@@ -1,354 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "Category_String.hpp"--#include <map>-#include <sstream>--#include "category-source.hpp"-#include "Category_AsBool.hpp"-#include "Category_Formatted.hpp"-#include "Category_Char.hpp"-#include "Category_Container.hpp"-#include "Category_ReadAt.hpp"-#include "Category_SubSequence.hpp"-#include "Category_Append.hpp"-#include "Category_Build.hpp"-#include "Category_Default.hpp"-#include "Category_DefaultOrder.hpp"-#include "Category_Order.hpp"-#include "Category_Equals.hpp"-#include "Category_LessThan.hpp"---#ifdef ZEOLITE_PUBLIC_NAMESPACE-namespace ZEOLITE_PUBLIC_NAMESPACE {-#endif // ZEOLITE_PUBLIC_NAMESPACE-namespace {-const int collection_String = 0;-} // namespace-const void* const Functions_String = &collection_String;-const ValueFunction& Function_String_subSequence = (*new ValueFunction{ 0, 2, 1, "String", "subSequence", Functions_String, 0 });-const TypeFunction& Function_String_builder = (*new TypeFunction{ 0, 0, 1, "String", "builder", Functions_String, 0 });-namespace {-class Category_String;-class Type_String;-class Value_String;-struct Category_String : public TypeCategory {- std::string CategoryName() const final { return "String"; }- Category_String() {- CycleCheck<Category_String>::Check();- CycleCheck<Category_String> marker(*this);- TRACE_FUNCTION("String (init @category)")- }- ReturnTuple Dispatch(const CategoryFunction& label, const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Category_String::*)(const ParamTuple&, const ValueTuple&);- return TypeCategory::Dispatch(label, params, args);- }-};-Category_String& CreateCategory_String() {- static auto& category = *new Category_String();- return category;-}-struct Type_String : public TypeInstance {- std::string CategoryName() const final { return parent.CategoryName(); }- void BuildTypeName(std::ostream& output) const final {- return TypeInstance::TypeNameFrom(output, parent);- }- Category_String& parent;- bool CanConvertFrom(const S<const TypeInstance>& from) const final {- std::vector<S<const TypeInstance>> args;- if (!from->TypeArgsForParent(parent, args)) return false;- if(args.size() != 0) {- FAIL() << "Wrong number of args (" << args.size() << ") for " << CategoryName();- }- return true;- }- void Params_String(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_AsBool(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_Formatted(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_ReadAt(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{GetType_Char(T_get())};- }- void Params_SubSequence(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{};- }- void Params_DefaultOrder(std::vector<S<const TypeInstance>>& args) const {- args = std::vector<S<const TypeInstance>>{GetType_Char(T_get())};- }- bool TypeArgsForParent(const TypeCategory& category, std::vector<S<const TypeInstance>>& args) const final {- using CallType = void(Type_String::*)(std::vector<S<const TypeInstance>>&)const;- static DispatchSingle<CallType> all_calls[] = {- DispatchSingle<CallType>(&GetCategory_String(), &Type_String::Params_String),- DispatchSingle<CallType>(&GetCategory_AsBool(), &Type_String::Params_AsBool),- DispatchSingle<CallType>(&GetCategory_Formatted(), &Type_String::Params_Formatted),- DispatchSingle<CallType>(&GetCategory_ReadAt(), &Type_String::Params_ReadAt),- DispatchSingle<CallType>(&GetCategory_SubSequence(), &Type_String::Params_SubSequence),- DispatchSingle<CallType>(&GetCategory_DefaultOrder(), &Type_String::Params_DefaultOrder),- DispatchSingle<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchSingle<CallType>* const call = DispatchSelect(table_lock, &category, all_calls);- if (call) {- (this->*call->value)(args);- return true;- }- return false;- }- Type_String(Category_String& p, Params<0>::Type params) : parent(p) {- CycleCheck<Type_String>::Check();- CycleCheck<Type_String> marker(*this);- TRACE_FUNCTION("String (init @type)")- }- ReturnTuple Dispatch(const S<TypeInstance>& self, const TypeFunction& label,- const ParamTuple& params, const ValueTuple& args) final {- using CallType = ReturnTuple(Type_String::*)(const ParamTuple&, const ValueTuple&);- static const CallType Table_Default[] = {- &Type_String::Call_default,- };- static const CallType Table_Equals[] = {- &Type_String::Call_equals,- };- static const CallType Table_LessThan[] = {- &Type_String::Call_lessThan,- };- static const CallType Table_String[] = {- &Type_String::Call_builder,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_Default, Table_Default),- DispatchTable<CallType>(Functions_Equals, Table_Equals),- DispatchTable<CallType>(Functions_LessThan, Table_LessThan),- DispatchTable<CallType>(Functions_String, Table_String),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(params, args);- }- }- return TypeInstance::Dispatch(self, label, params, args);- }- ReturnTuple Call_default(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_builder(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_equals(const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_lessThan(const ParamTuple& params, const ValueTuple& args);-};-S<Type_String> CreateType_String(Params<0>::Type params) {- static const auto cached = S_get(new Type_String(CreateCategory_String(), Params<0>::Type()));- return cached;-}-struct Value_String : public TypeValue {- Value_String(S<Type_String> p, const PrimString& value) : parent(p), value_(value) {}- ReturnTuple Dispatch(const S<TypeValue>& self, const ValueFunction& label, const ParamTuple& params,const ValueTuple& args) final {- using CallType = ReturnTuple(Value_String::*)(const S<TypeValue>&, const ParamTuple&, const ValueTuple&);- static const CallType Table_AsBool[] = {- &Value_String::Call_asBool,- };- static const CallType Table_DefaultOrder[] = {- &Value_String::Call_defaultOrder,- };- static const CallType Table_Formatted[] = {- &Value_String::Call_formatted,- };- static const CallType Table_ReadAt[] = {- &Value_String::Call_readAt,- };- static const CallType Table_Container[] = {- &Value_String::Call_size,- };- static const CallType Table_String[] = {- &Value_String::Call_subSequence,- };- static const CallType Table_SubSequence[] = {- &Value_String::Call_subSequence,- };- static DispatchTable<CallType> all_tables[] = {- DispatchTable<CallType>(Functions_AsBool, Table_AsBool),- DispatchTable<CallType>(Functions_Container, Table_Container),- DispatchTable<CallType>(Functions_DefaultOrder, Table_DefaultOrder),- DispatchTable<CallType>(Functions_Formatted, Table_Formatted),- DispatchTable<CallType>(Functions_ReadAt, Table_ReadAt),- DispatchTable<CallType>(Functions_String, Table_String),- DispatchTable<CallType>(Functions_SubSequence, Table_SubSequence),- DispatchTable<CallType>(),- };- std::atomic_bool table_lock{0};- const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);- if (table) {- if (label.function_num < 0 || label.function_num >= table->size) {- FAIL() << "Bad function call " << label;- } else {- return (this->*table->table[label.function_num])(self, params, args);- }- }- return TypeValue::Dispatch(self, label, params, args);- }- std::string CategoryName() const final { return parent->CategoryName(); }- const PrimString& AsString() const final { return value_; }- ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_defaultOrder(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_size(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- ReturnTuple Call_subSequence(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args);- const S<Type_String> parent;- const PrimString value_;-};--class Value_StringBuilder : public TypeValue {- public:- std::string CategoryName() const final { return "StringBuilder"; }-- ReturnTuple Dispatch(const S<TypeValue>& self,- const ValueFunction& label,- const ParamTuple& params, const ValueTuple& args) final {- if (args.Size() != label.arg_count) {- FAIL() << "Wrong number of args";- }- if (params.Size() != label.param_count){- FAIL() << "Wrong number of params";- }- if (&label == &Function_Append_append) {- TRACE_FUNCTION("StringBuilder.append")- std::lock_guard<std::mutex> lock(mutex);- output_ << args.At(0)->AsString();- return ReturnTuple(self);- }- if (&label == &Function_Build_build) {- TRACE_FUNCTION("StringBuilder.build")- std::lock_guard<std::mutex> lock(mutex);- return ReturnTuple(Box_String(output_.str()));- }- return TypeValue::Dispatch(self, label, params, args);- }-- private:- std::mutex mutex;- std::ostringstream output_;-};--struct StringOrder : public AnonymousOrder {- StringOrder(S<TypeValue> container, const std::string& s)- : AnonymousOrder(container, Function_Order_next, Function_Order_get), value(s) {}-- S<TypeValue> Call_next(const S<TypeValue>& self) final {- if (index+1 >= value.size()) {- return Var_empty;- } else {- ++index;- return self;- }- }-- S<TypeValue> Call_get(const S<TypeValue>& self) final {- if (index >= value.size()) FAIL() << "iterated past end of String";- return Box_Char(value[index]);- }-- const std::string& value;- int index = 0;-};--ReturnTuple Type_String::Call_default(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.default")- return ReturnTuple(Box_String(""));-}-ReturnTuple Type_String::Call_builder(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.builder")- return ReturnTuple(S<TypeValue>(new Value_StringBuilder));-}-ReturnTuple Type_String::Call_equals(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.equals")- const S<TypeValue>& Var_arg1 = (args.At(0));- const S<TypeValue>& Var_arg2 = (args.At(1));- return ReturnTuple(Box_Bool(Var_arg1->AsString()==Var_arg2->AsString()));-}-ReturnTuple Type_String::Call_lessThan(const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.lessThan")- const S<TypeValue>& Var_arg1 = (args.At(0));- const S<TypeValue>& Var_arg2 = (args.At(1));- return ReturnTuple(Box_Bool(Var_arg1->AsString()<Var_arg2->AsString()));-}-ReturnTuple Value_String::Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.asBool")- return ReturnTuple(Box_Bool(value_.size() != 0));-}-ReturnTuple Value_String::Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.formatted")- return ReturnTuple(Var_self);-}-ReturnTuple Value_String::Call_defaultOrder(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.defaultOrder")- if (value_.empty()) {- return ReturnTuple(Var_empty);- } else {- return ReturnTuple(S_get(new StringOrder(Var_self, value_)));- }-}-ReturnTuple Value_String::Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.readAt")- const PrimInt Var_arg1 = (args.At(0))->AsInt();- if (Var_arg1 < 0 || Var_arg1 >= value_.size()) {- FAIL() << "Read position " << Var_arg1 << " is out of bounds";- }- return ReturnTuple(Box_Char(value_[Var_arg1]));-}-ReturnTuple Value_String::Call_size(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.size")- return ReturnTuple(Box_Int(value_.size()));-}-ReturnTuple Value_String::Call_subSequence(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) {- TRACE_FUNCTION("String.subSequence")- const PrimInt Var_arg1 = (args.At(0))->AsInt();- const PrimInt Var_arg2 = (args.At(1))->AsInt();- if (Var_arg1 < 0 || Var_arg1 > value_.size()) {- FAIL() << "Subsequence position " << Var_arg1 << " is out of bounds";- }- if (Var_arg2 < 0 || Var_arg1 + Var_arg2 > value_.size()) {- FAIL() << "Subsequence size " << Var_arg2 << " is invalid";- }- return ReturnTuple(Box_String(value_.substr(Var_arg1,Var_arg2)));-}-} // namespace-TypeCategory& GetCategory_String() {- return CreateCategory_String();-}-S<TypeInstance> GetType_String(Params<0>::Type params) {- return CreateType_String(params);-}-#ifdef ZEOLITE_PUBLIC_NAMESPACE-} // namespace ZEOLITE_PUBLIC_NAMESPACE-using namespace ZEOLITE_PUBLIC_NAMESPACE;-#endif // ZEOLITE_PUBLIC_NAMESPACE---S<TypeValue> Box_String(const PrimString& value) {- return S_get(new Value_String(CreateType_String(Params<0>::Type()), value));-}
base/builtin.0rp view
@@ -102,6 +102,14 @@ defines Equals<String> defines LessThan<String> + // Create a new String as an immutable copy of a CharBuffer.+ //+ // Notes:+ // - Changing the data in the CharBuffer after copying will not result in+ // modifications to the String returned here.+ // - Data will be copied verbatim, even if some characters are null.+ @type fromCharBuffer (CharBuffer) -> (String)+ // Get a builder to create a string using concatenation. // // Example:@@ -110,6 +118,28 @@ @type builder () -> ([Append<String>&Build<String>]) } +// Built-in fixed-size buffer of byte data.+//+// Literals: None.+concrete CharBuffer {+ refines ReadAt<Char>+ refines WriteAt<Char>++ // Create a new buffer with a fixed size.+ //+ // Notes:+ // - The implementation does not guarantee that the values will be zeroed.+ @type new (Int) -> (CharBuffer)++ // Resize the buffer to the specified size.+ //+ // Notes:+ // - The implementation does not guarantee that the values will be zeroed.+ // Specifically, resizing down and then back up again could either preserve+ // or overwrite any of the data.+ @value resize (Int) -> (CharBuffer)+}+ // Convertible to Bool. @value interface AsBool { // Convert the value to Bool.@@ -203,6 +233,17 @@ // Return the value at the given index. readAt (Int) -> (#x)+}++// Random-access writing to a container.+//+// Params:+// - #x: The value type contained.+@value interface WriteAt<#x|> {+ refines Container++ // Write the value at the given index and return self.+ writeAt (Int,#x) -> (#self) } // Sequence that can be subsequenced.
− base/category-source.cpp
@@ -1,292 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2021 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "category-source.hpp"--#include <algorithm>--#include "logging.hpp"---namespace {--struct OptionalEmpty : public TypeValue {- ReturnTuple Dispatch(const S<TypeValue>& self,- const ValueFunction& label,- const ParamTuple& params, const ValueTuple& args) final {- FAIL() << "Function called on empty value";- __builtin_unreachable();- }-- std::string CategoryName() const final { return "empty"; }-- bool Present() const final { return false; }-};--struct Type_Intersect : public TypeInstance {- Type_Intersect(L<S<const TypeInstance>> params) : params_(params.begin(), params.end()) {}-- std::string CategoryName() const final { return "(intersection)"; }-- void BuildTypeName(std::ostream& output) const final {- if (params_.empty()) {- output << "any";- } else {- output << "[";- bool first = true;- for (const auto param : params_) {- if (!first) output << "&";- first = false;- param->BuildTypeName(output);- }- output << "]";- }- }-- MergeType InstanceMergeType() const final- { return MergeType::INTERSECT; }-- std::vector<S<const TypeInstance>> MergedTypes() const final- { return params_; }-- const L<S<const TypeInstance>> params_;-};--struct Type_Union : public TypeInstance {- Type_Union(L<S<const TypeInstance>> params) : params_(params.begin(), params.end()) {}-- std::string CategoryName() const final { return "(union)"; }-- void BuildTypeName(std::ostream& output) const final {- if (params_.empty()) {- output << "all";- } else {- output << "[";- bool first = true;- for (const auto param : params_) {- if (!first) output << "|";- first = false;- param->BuildTypeName(output);- }- output << "]";- }- }-- MergeType InstanceMergeType() const final- { return MergeType::UNION; }-- std::vector<S<const TypeInstance>> MergedTypes() const final- { return params_; }-- const L<S<const TypeInstance>> params_;-};--L<const TypeInstance*> ParamsToKey(const L<S<const TypeInstance>>& params) {- L<const TypeInstance*> key;- for (const auto& param : params) {- key.push_back(param.get());- }- std::sort(key.begin(), key.end());- return key;-}--} // namespace---S<TypeInstance> Merge_Intersect(L<S<const TypeInstance>> params) {- static auto& cache = *new std::map<L<const TypeInstance*>,S<Type_Intersect>>();- auto& cached = cache[ParamsToKey(params)];- S<Type_Intersect> type = cached;- if (!type) { cached = type = S_get(new Type_Intersect(params)); }- return type;-}--S<TypeInstance> Merge_Union(L<S<const TypeInstance>> params) {- static auto& cache = *new std::map<L<const TypeInstance*>,S<Type_Union>>();- auto& cached = cache[ParamsToKey(params)];- S<Type_Union> type = cached;- if (!type) { cached = type = S_get(new Type_Union(params)); }- return type;-}--const S<TypeInstance>& GetMerged_Any() {- static const auto instance = Merge_Intersect(L_get<S<const TypeInstance>>());- return instance;-}--const S<TypeInstance>& GetMerged_All() {- static const auto instance = Merge_Union(L_get<S<const TypeInstance>>());- return instance;-}---const S<TypeValue>& Var_empty = *new S<TypeValue>(new OptionalEmpty());---ReturnTuple TypeCategory::Dispatch(const CategoryFunction& label,- const ParamTuple& params, const ValueTuple& args) {- FAIL() << CategoryName() << " does not implement " << label;- __builtin_unreachable();-}--ReturnTuple TypeInstance::Dispatch(const S<TypeInstance>& self, const TypeFunction& label,- const ParamTuple& params, const ValueTuple& args) {- FAIL() << CategoryName() << " does not implement " << label;- __builtin_unreachable();-}--ReturnTuple TypeValue::Dispatch(const S<TypeValue>& self, const ValueFunction& label,- const ParamTuple& params, const ValueTuple& args) {- FAIL() << CategoryName() << " does not implement " << label;- __builtin_unreachable();-}--bool TypeInstance::CanConvert(const S<const TypeInstance>& x,- const S<const TypeInstance>& y) {- // See pairMergeTree for the ordering here.- // TODO: Consider using a cache here, since the check could be expensive.- if (x.get() == y.get()) {- return true;- } else if (x->InstanceMergeType() == MergeType::INTERSECT &&- y->InstanceMergeType() == MergeType::UNION) {- for (const auto& left : x->MergedTypes()) {- if (left->InstanceMergeType() == MergeType::SINGLE) {- for (const auto& right : y->MergedTypes()) {- if (right->InstanceMergeType() == MergeType::SINGLE) {- if (TypeInstance::CanConvert(left, right)) {- return true;- }- }- }- }- }- for (const auto& left : x->MergedTypes()) {- if (TypeInstance::CanConvert(left, y)) {- return true;- }- }- for (const auto right : y->MergedTypes()) {- if (TypeInstance::CanConvert(x, right)) {- return true;- }- }- return false;- } else if (y->InstanceMergeType() == MergeType::INTERSECT) {- for (const auto& right : y->MergedTypes()) {- if (!TypeInstance::CanConvert(x, right)) {- return false;- }- }- return true;- } else if (x->InstanceMergeType() == MergeType::UNION) {- for (const auto& left : x->MergedTypes()) {- if (!TypeInstance::CanConvert(left, y)) {- return false;- }- }- return true;- } else if (x->InstanceMergeType() == MergeType::INTERSECT) {- for (const auto& left : x->MergedTypes()) {- if (TypeInstance::CanConvert(left, y)) {- return true;- }- }- return false;- } else if (y->InstanceMergeType() == MergeType::UNION) {- for (const auto right : y->MergedTypes()) {- if (TypeInstance::CanConvert(x, right)) {- return true;- }- }- return false;- } else {- return y->CanConvertFrom(x);- }-}--bool TypeValue::Present(S<TypeValue> target) {- if (target == nullptr) {- FAIL() << "Builtin called on null value";- }- return target->Present();-}--S<TypeValue> TypeValue::Require(S<TypeValue> target) {- if (target == nullptr) {- FAIL() << "Builtin called on null value";- }- if (!target->Present()) {- FAIL() << "Cannot require empty value";- }- return target;-}--S<TypeValue> TypeValue::Strong(W<TypeValue> target) {- const auto strong = target.lock();- return strong? strong : Var_empty;-}--bool TypeValue::AsBool() const {- FAIL() << CategoryName() << " is not a Bool value";- __builtin_unreachable();-}--const PrimString& TypeValue::AsString() const {- FAIL() << CategoryName() << " is not a String value";- __builtin_unreachable();-}--PrimChar TypeValue::AsChar() const {- FAIL() << CategoryName() << " is not a Char value";- __builtin_unreachable();-}--PrimInt TypeValue::AsInt() const {- FAIL() << CategoryName() << " is not an Int value";- __builtin_unreachable();-}--PrimFloat TypeValue::AsFloat() const {- FAIL() << CategoryName() << " is not a Float value";- __builtin_unreachable();-}--bool TypeValue::Present() const {- return true;-}--AnonymousOrder::AnonymousOrder(const S<TypeValue> cont,- const ValueFunction& func_next,- const ValueFunction& func_get)- : container(cont), function_next(func_next), function_get(func_get) {}--std::string AnonymousOrder::CategoryName() const { return "AnonymousOrder"; }--ReturnTuple AnonymousOrder::Dispatch(- const S<TypeValue>& self, const ValueFunction& label,- const ParamTuple& params, const ValueTuple& args) {- if (&label == &function_next) {- TRACE_FUNCTION("AnonymousOrder.next")- return ReturnTuple(Call_next(self));- }- if (&label == &function_get) {- TRACE_FUNCTION("AnonymousOrder.get")- return ReturnTuple(Call_get(self));- }- return TypeValue::Dispatch(self, label, params, args);-}
base/category-source.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry+Copyright 2019-2021 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -19,17 +19,13 @@ #ifndef CATEGORY_SOURCE_HPP_ #define CATEGORY_SOURCE_HPP_ -#include <algorithm>-#include <atomic> #include <iostream> // For occasional debugging output in generated code. #include <map>-#include <mutex> #include <sstream> #include <vector> #include "types.hpp" #include "function.hpp"-#include "cycle-check.hpp" #define BUILTIN_FAIL(e) { \@@ -176,6 +172,7 @@ virtual bool AsBool() const; virtual const PrimString& AsString() const; virtual PrimChar AsChar() const;+ virtual PrimCharBuffer& AsCharBuffer(); virtual PrimInt AsInt() const; virtual PrimFloat AsFloat() const; @@ -194,29 +191,6 @@ const ParamTuple& params, const ValueTuple& args); }; -template <int P, class T>-class InstanceCache {- public:- using Creator = std::function<S<T>(typename Params<P>::Type)>;-- InstanceCache(const Creator& create) : create_(create) {}-- S<T> GetOrCreate(typename Params<P>::Type params) {- std::lock_guard<std::mutex> lock(mutex_);- auto& cached = cache_[GetKeyFromParams<P>(params)];- S<T> type = cached;- if (!type) {- cached = type = create_(params);- }- return type;- }-- private:- const Creator create_;- std::mutex mutex_;- std::map<typename ParamsKey<P>::Type, S<T>> cache_;-};- class AnonymousOrder : public TypeValue { protected: // Passing in the function labels allows linking without depending on Order@@ -241,54 +215,5 @@ const ValueFunction& function_next; const ValueFunction& function_get; };--template<class F>-struct DispatchTable {- constexpr DispatchTable() : key(nullptr), table(nullptr), size(0) {}-- template<int S>- DispatchTable(const void* k, const F(&t)[S]) : key(k), table(t), size(S) {}-- bool operator < (const DispatchTable<F>& other) const { return key < other.key; }-- const void* key;- const F* table;- int size;-};--template<class F>-struct DispatchSingle {- constexpr DispatchSingle() : key(nullptr), value() {}-- DispatchSingle(const void* k, const F v) : key(k), value(v) {}-- bool operator < (const DispatchSingle<F>& other) const { return key < other.key; }-- const void* key;- F value;- int size;-};--template<class T, int S>-const T* DispatchSelect(std::atomic_bool& lock, const void* key, T(&table)[S]) {- if (S < 2) return nullptr;- while (lock.exchange(true));- if (table[0].key != nullptr) {- std::sort(table, table+S);- }- lock.exchange(false);- int i = 1, j = S;- while (j-i > 1) {- const int k = (i+j)/2;- if (table[k].key < key) {- i = k;- } else if (table[k].key > key) {- j = k;- } else {- return &table[k];- }- }- return (table[i].key == key)? &table[i] : nullptr;-} #endif // CATEGORY_SOURCE_HPP_
base/function.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry+Copyright 2019-2021 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -28,7 +28,7 @@ const int return_count; const char* const category; const char* const function;- const void* const collection;+ const CollectionType collection; const int function_num; }; @@ -38,7 +38,7 @@ const int return_count; const char* const category; const char* const function;- const void* const collection;+ const CollectionType collection; const int function_num; }; @@ -48,12 +48,12 @@ const int return_count; const char* const category; const char* const function;- const void* const collection;+ const CollectionType collection; const int function_num; }; inline std::ostream& operator << (std::ostream& output, const CategoryFunction& func) {- return output << func.category << "." << func.function;+ return output << func.category << ":" << func.function; } inline std::ostream& operator << (std::ostream& output, const TypeFunction& func) {
+ base/internal.hpp view
@@ -0,0 +1,151 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#ifndef INTERNAL_HPP_+#define INTERNAL_HPP_++#include <algorithm>+#include <atomic>++#include "category-source.hpp"+#include "cycle-check.hpp"+++#define COLLECTION_ID(vp) (int) 1000000009 * (long) (vp)++template <int P, class T>+class InstanceCache {+ public:+ using Creator = std::function<S<T>(typename Params<P>::Type)>;++ InstanceCache(const Creator& create) : create_(create) {}++ S<T> GetOrCreate(typename Params<P>::Type params) {+ while (lock_.test_and_set(std::memory_order_acquire));+ auto& cached = cache_[GetKeyFromParams<P>(params)];+ S<T> type = cached;+ if (!type) {+ cached = type = create_(params);+ }+ lock_.clear(std::memory_order_release);+ return type;+ }++ private:+ const Creator create_;+ std::atomic_flag lock_ = ATOMIC_FLAG_INIT;+ std::map<typename ParamsKey<P>::Type, S<T>> cache_;+};++template<class F>+struct DispatchTable {+ constexpr DispatchTable() : key(), table(nullptr), size(0) {}++ template<int S>+ DispatchTable(CollectionType k, const F(&t)[S]) : key(k), table(t), size(S) {}++ inline bool operator < (const DispatchTable<F>& other) const { return key < other.key; }++ CollectionType key;+ const F* table;+ int size;+};++template<class F>+struct DispatchSingle {+ constexpr DispatchSingle() : key(nullptr), value() {}++ DispatchSingle(const void* k, const F v) : key(k), value(v) {}++ inline bool operator < (const DispatchSingle<F>& other) const { return key < other.key; }++ const void* key;+ F value;+};++struct StaticSort {+ template<class T, int S>+ StaticSort(T(&table)[S]) {+ std::sort(table, table+S);+ }+};++template<class T>+struct LoopLimit {};++template<class F>+struct LoopLimit<DispatchTable<F>> {+ // See function-calls.0rt for tests.+ static constexpr int max = 15;+};++template<class F>+struct LoopLimit<DispatchSingle<F>> {+ // See function-calls.0rt for tests.+ static constexpr int max = 15;+};++template<bool L, class T, int S>+struct DispatchChoice {};++template<class T>+struct DispatchChoice<true, T, 0> {+ template<class K>+ static const T* Select(K key, T* table) {+ return nullptr;+ }+};+template<class T, int S>+struct DispatchChoice<true, T, S> {+ template<class K>+ static const T* Select(K key, T* table) {+ if (table->key == key) {+ return table;+ }+ return DispatchChoice<true, T, S-1>::Select(key, table+1);+ }+};++template<class T, int S>+struct DispatchChoice<false, T, S> {+ template<class K>+ static const T* Select(K key, T* table) {+ int i = 0, j = S, k;+ while ((k = (i+j)/2) > i) {+ if (table[k].key < key) {+ i = k;+ } else if (table[k].key > key) {+ j = k;+ } else {+ return &table[k];+ }+ }+ if (table[k].key == key) {+ return &table[k];+ } else {+ return nullptr;+ }+ }+};++template<class K, class T, int S>+const T* DispatchSelect(K key, T(&table)[S]) {+ return DispatchChoice<(S <= LoopLimit<T>::max), T, S>::Select(key, table);+}++#endif // INTERNAL_HPP_
− base/logging.cpp
@@ -1,234 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "logging.hpp"--#include <cassert>-#include <chrono>-#include <csignal>-#include <iomanip>-#include <iostream>---LogThenCrash::LogThenCrash(bool fail, const std::string& condition)- : fail_(fail), signal_(SIGABRT), condition_(condition) {}--LogThenCrash::LogThenCrash(bool fail, int signal)- : fail_(fail), signal_(signal) {}--LogThenCrash::~LogThenCrash() {- if (fail_) {- std::signal(signal_, SIG_DFL);- if (Argv::ArgCount() > 0) {- std::cerr << Argv::GetArgAt(0) << ": ";- }- std::cerr << "Failed condition";- if (!condition_.empty()) {- std::cerr << " '" << condition_ << "'";- }- std::cerr << ": " << output_.str() << std::endl;- PrintTrace(TraceContext::GetTrace());- const TraceList creation_trace = TraceCreation::GetTrace();- if (!creation_trace.empty()) {- std::cerr << TraceCreation::GetType() << " value originally created at:" << std::endl;- PrintTrace(creation_trace);- }- std::raise(signal_);- }-}--// static-void LogThenCrash::PrintTrace(const TraceList &call_trace) {- for (const auto& trace : call_trace) {- const std::string message = trace();- if (!message.empty()) {- std::cerr << " " << message << std::endl;- }- }-}--// TODO: Should only be available used if POSIX is defined.-void TraceOnSignal(int signal) {- LogThenCrash(true,signal) << "Recieved signal " << signal;-}--// TODO: Should only be available used if POSIX is defined.-void SetSignalHandler() {-#ifdef SIGINT- std::signal(SIGINT, &TraceOnSignal);-#endif-#ifdef SIGILL- std::signal(SIGILL, &TraceOnSignal);-#endif-#ifdef SIGABRT- std::signal(SIGABRT, &TraceOnSignal);-#endif-#ifdef SIGFPE- std::signal(SIGFPE, &TraceOnSignal);-#endif-#ifdef SIGQUIT- std::signal(SIGQUIT, &TraceOnSignal);-#endif-#ifdef SIGSEGV- std::signal(SIGSEGV, &TraceOnSignal);-#endif-#ifdef SIGPIPE- std::signal(SIGPIPE, &TraceOnSignal);-#endif-#ifdef SIGALRM- std::signal(SIGALRM, &TraceOnSignal);-#endif-#ifdef SIGTERM- std::signal(SIGTERM, &TraceOnSignal);-#endif-#ifdef SIGUSR1- std::signal(SIGUSR1, &TraceOnSignal);-#endif-#ifdef SIGUSR2- std::signal(SIGUSR2, &TraceOnSignal);-#endif-}---TraceList TraceContext::GetTrace() {- TraceList trace;- const TraceContext* current = GetCurrent();- while (current) {- current->AppendTrace(trace);- current = current->GetNext();- }- return trace;-}---void SourceContext::SetLocal(const char* at) {- at_ = at;- LogCalls::MaybeLogCall(name_, at_);-}--void SourceContext::AppendTrace(TraceList& trace) const {- const char* const name = name_;- const char* const at = at_;- trace.push_back([name,at]() {- std::ostringstream output;- if (at == nullptr || at[0] == 0x00) {- output << "From " << name;- } else {- output << "From " << name << " at " << at;- }- return output.str();- });-}--const TraceContext* SourceContext::GetNext() const {- return capture_to_.Previous();-}---void CleanupContext::SetLocal(const char* at) {- at_ = at;-}--void CleanupContext::AppendTrace(TraceList& trace) const {- const char* const at = at_;- trace.push_back([at]() {- std::ostringstream output;- if (at == nullptr || at[0] == 0x00) {- output << "In cleanup block";- } else {- output << "In cleanup block at " << at;- }- return output.str();- });-}--const TraceContext* CleanupContext::GetNext() const {- return capture_to_.Previous();-}--int Argv::ArgCount() {- if (GetCurrent()) {- return GetCurrent()->GetArgs().size();- } else {- return 0;- }-}--const std::string& Argv::GetArgAt(int pos) {- if (pos < 0 || pos >= ArgCount()) {- FAIL() << "Argv index " << pos << " is out of bounds";- __builtin_unreachable();- } else {- return GetCurrent()->GetArgs()[pos];- }-}--const std::vector<std::string>& ProgramArgv::GetArgs() const {- return argv_;-}--std::string FixCsvString(const char* string) {- std::string fixed;- while (*string) {- switch (*string) {- case '\\':- break;- case '"':- fixed.push_back('\'');- break;- default:- fixed.push_back(*string);- break;- }- ++string;- }- return fixed;-}--unsigned int UniqueId() {- const auto time = std::chrono::steady_clock::now().time_since_epoch();- return (1000000009 * std::chrono::duration_cast<std::chrono::microseconds>(time).count());-}--LogCallsToFile::LogCallsToFile(std::string filename)- : unique_id_(UniqueId()),- filename_(std::move(filename)),- log_file_(filename_.empty()?- nullptr :- new std::fstream(filename_, std::ios::in |- std::ios::out |- std::ios::ate |- std::ios::app)),- cross_and_capture_to_(this) {- if (log_file_) {- if (!*log_file_) {- FAIL() << "Failed to open call log " << filename_ << " for writing";- }- }-}--void LogCallsToFile::LogCall(const char* name, const char* at) {- if (log_file_) {- std::lock_guard<std::mutex> lock(mutex_);- const auto time = std::chrono::steady_clock::now().time_since_epoch();- *log_file_ << std::chrono::duration_cast<std::chrono::microseconds>(time).count() << ","- << unique_id_ << ","- << "\"" << FixCsvString(name) << "\"" << ","- << "\"" << FixCsvString(at) << "\"" << std::endl;- }-}
+ base/pooled.hpp view
@@ -0,0 +1,109 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#ifndef POOLED_HPP_+#define POOLED_HPP_+++template<class T>+class PoolStorage {+ public:+ inline T* data() const {+ return (T*) (this + 1);+ }++ const int size = 0;+ PoolStorage* next = nullptr;++private:+ template<class> friend class PoolManager;++ inline PoolStorage(int s, PoolStorage* n) : size(s), next(n) {}++ inline ~PoolStorage() {}++ PoolStorage(const PoolStorage&) = delete;+ PoolStorage& operator = (const PoolStorage&) = delete;+ PoolStorage(PoolStorage&&) = delete;+ PoolStorage& operator = (PoolStorage&&) = delete;+};++template<class T>+struct PoolManager {};++template<class T>+class PoolArray {+ friend class ArgTuple;+ friend class ReturnTuple;+ friend class ParamTuple;++ constexpr PoolArray() : array_(nullptr) {}++ PoolArray(int size) : array_(PoolManager<T>::Take(size)) {}++ PoolArray(PoolArray&& other) : array_(other.array_) {+ other.array_ = nullptr;+ }++ PoolArray& operator = (PoolArray&& other) {+ array_ = other.array_;+ other.array_ = nullptr;+ return *this;+ }++ const T& operator [] (int i) const {+ if (!array_ || i < 0 || i >= array_->size) {+ FAIL() << "Bad array index " << i;+ }+ return array_->data()[i];+ }++ T& operator [] (int i) {+ if (!array_ || i < 0 || i >= array_->size) {+ FAIL() << "Bad array index " << i;+ }+ return array_->data()[i];+ }++ template<class...Ts>+ inline void Init(Ts... data) {+ if (sizeof...(Ts) > array_->size) {+ FAIL() << "Too many init values " << sizeof...(Ts);+ }+ InitRec(0, std::move(data)...);+ }++ template<class...Ts>+ inline void InitRec(int i, T arg, Ts... data) {+ array_->data()[i] = std::move(arg);+ InitRec(i+1, std::move(data)...);+ }++ inline void InitRec(int i) {}++ ~PoolArray() {+ PoolManager<T>::Return(array_);+ }++ PoolArray(const PoolArray&) = delete;+ PoolArray& operator = (const PoolArray&) = delete;++ PoolStorage<T>* array_;+};++#endif // POOLED_HPP_
+ base/src/Extension_Bool.cpp view
@@ -0,0 +1,102 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Bool.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Default.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Int.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Bool : public Category_Bool {+};++struct ExtType_Bool : public Type_Bool {+ inline ExtType_Bool(Category_Bool& p, Params<0>::Type params) : Type_Bool(p, params) {}++ ReturnTuple Call_default(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Bool.default")+ return ReturnTuple(Box_Bool(false));+ }++ ReturnTuple Call_equals(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Bool.equals")+ const bool Var_arg1 = (args.At(0))->AsBool();+ const bool Var_arg2 = (args.At(1))->AsBool();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }+};++struct ExtValue_Bool : public Value_Bool {+ inline ExtValue_Bool(S<Type_Bool> p, bool value) : Value_Bool(p), value_(value) {}++ ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Bool.asBool")+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Bool.asFloat")+ return ReturnTuple(Box_Float(value_ ? 1.0 : 0.0));+ }++ ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Bool.asInt")+ return ReturnTuple(Box_Int(value_? 1 : 0));+ }++ ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Bool.formatted")+ return ReturnTuple(Box_String(value_? "true" : "false"));+ }++ bool AsBool() const final { return value_; }++ const bool value_;+};++const S<TypeValue>& Var_true = *new S<TypeValue>(new ExtValue_Bool(CreateType_Bool(Params<0>::Type()), true));+const S<TypeValue>& Var_false = *new S<TypeValue>(new ExtValue_Bool(CreateType_Bool(Params<0>::Type()), false));++Category_Bool& CreateCategory_Bool() {+ static auto& category = *new ExtCategory_Bool();+ return category;+}+S<Type_Bool> CreateType_Bool(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_Bool(CreateCategory_Bool(), Params<0>::Type()));+ return cached;+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE++S<TypeValue> Box_Bool(bool value) {+ return value? Var_true : Var_false;+}
+ base/src/Extension_Char.cpp view
@@ -0,0 +1,114 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_Char.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsChar.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Char.hpp"+#include "Category_Default.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Char : public Category_Char {+};++struct ExtType_Char : public Type_Char {+ inline ExtType_Char(Category_Char& p, Params<0>::Type params) : Type_Char(p, params) {}++ ReturnTuple Call_default(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.default")+ return ReturnTuple(Box_Char('\0'));+ }++ ReturnTuple Call_equals(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.equals")+ const PrimChar Var_arg1 = (args.At(0))->AsChar();+ const PrimChar Var_arg2 = (args.At(1))->AsChar();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.lessThan")+ const PrimChar Var_arg1 = (args.At(0))->AsChar();+ const PrimChar Var_arg2 = (args.At(1))->AsChar();+ return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));+ }+};++struct ExtValue_Char : public Value_Char {+ inline ExtValue_Char(S<Type_Char> p, PrimChar value) : Value_Char(p), value_(value) {}++ ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.asBool")+ return ReturnTuple(Box_Bool(value_ != '\0'));+ }++ ReturnTuple Call_asChar(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.asChar")+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.asFloat")+ return ReturnTuple(Box_Float(value_));+ }++ ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.asInt")+ return ReturnTuple(Box_Int(value_));+ }++ ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Char.formatted")+ return ReturnTuple(Box_String(PrimString(1,value_)));+ }++ PrimChar AsChar() const final { return value_; }++ const PrimChar value_;+};++Category_Char& CreateCategory_Char() {+ static auto& category = *new ExtCategory_Char();+ return category;+}+S<Type_Char> CreateType_Char(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_Char(CreateCategory_Char(), Params<0>::Type()));+ return cached;+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE++S<TypeValue> Box_Char(PrimChar value) {+ return S_get(new ExtValue_Char(CreateType_Char(Params<0>::Type()), value));+}
+ base/src/Extension_CharBuffer.cpp view
@@ -0,0 +1,110 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_CharBuffer.hpp"+#include "Category_Char.hpp"+#include "Category_CharBuffer.hpp"+#include "Category_Container.hpp"+#include "Category_Int.hpp"+#include "Category_ReadAt.hpp"+#include "Category_WriteAt.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++S<TypeValue> CreateValue_CharBuffer(S<Type_CharBuffer> parent, PrimCharBuffer buffer);++struct ExtCategory_CharBuffer : public Category_CharBuffer {+};++struct ExtType_CharBuffer : public Type_CharBuffer {+ inline ExtType_CharBuffer(Category_CharBuffer& p, Params<0>::Type params) : Type_CharBuffer(p, params) {}++ ReturnTuple Call_new(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("CharBuffer.new")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ if (Var_arg1 < 0) {+ FAIL() << "Buffer size " << Var_arg1 << " is invalid";+ }+ return ReturnTuple(CreateValue_CharBuffer(CreateType_CharBuffer(Params<0>::Type()), PrimCharBuffer(Var_arg1,'\0')));+ }+};++struct ExtValue_CharBuffer : public Value_CharBuffer {+ inline ExtValue_CharBuffer(S<Type_CharBuffer> p, PrimCharBuffer value) : Value_CharBuffer(p), value_(std::move(value)) {}++ ReturnTuple Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("CharBuffer.readAt")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ if (Var_arg1 < 0 || Var_arg1 >= AsCharBuffer().size()) {+ FAIL() << "Read position " << Var_arg1 << " is out of bounds";+ }+ return ReturnTuple(Box_Char(AsCharBuffer()[Var_arg1]));+ }++ ReturnTuple Call_resize(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("CharBuffer.resize")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ if (Var_arg1 < 0) {+ FAIL() << "Buffer size " << Var_arg1 << " is invalid";+ } else {+ value_.resize(Var_arg1);+ }+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_size(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("CharBuffer.size")+ return ReturnTuple(Box_Int(value_.size()));+ }++ ReturnTuple Call_writeAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("CharBuffer.writeAt")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ const PrimChar Var_arg2 = (args.At(1))->AsChar();+ if (Var_arg1 < 0 || Var_arg1 >= value_.size()) {+ FAIL() << "Write position " << Var_arg1 << " is out of bounds";+ } else {+ value_[Var_arg1] = Var_arg2;+ }+ return ReturnTuple(Var_self);+ }++ PrimCharBuffer& AsCharBuffer() final { return value_; }++ PrimCharBuffer value_;+};++Category_CharBuffer& CreateCategory_CharBuffer() {+ static auto& category = *new ExtCategory_CharBuffer();+ return category;+}+S<Type_CharBuffer> CreateType_CharBuffer(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_CharBuffer(CreateCategory_CharBuffer(), Params<0>::Type()));+ return cached;+}+S<TypeValue> CreateValue_CharBuffer(S<Type_CharBuffer> parent, PrimCharBuffer value) {+ return S_get(new ExtValue_CharBuffer(parent, std::move(value)));+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE
+ base/src/Extension_Float.cpp view
@@ -0,0 +1,111 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include <sstream>++#include "category-source.hpp"+#include "Streamlined_Float.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Default.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Float : public Category_Float {+};++struct ExtType_Float : public Type_Float {+ inline ExtType_Float(Category_Float& p, Params<0>::Type params) : Type_Float(p, params) {}++ ReturnTuple Call_default(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Float.default")+ return ReturnTuple(Box_Float(0.0));+ }++ ReturnTuple Call_equals(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Float.equals")+ const PrimFloat Var_arg1 = (args.At(0))->AsFloat();+ const PrimFloat Var_arg2 = (args.At(1))->AsFloat();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Float.lessThan")+ const PrimFloat Var_arg1 = (args.At(0))->AsFloat();+ const PrimFloat Var_arg2 = (args.At(1))->AsFloat();+ return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));+ }+};++struct ExtValue_Float : public Value_Float {+ inline ExtValue_Float(S<Type_Float> p, PrimFloat value) : Value_Float(p), value_(value) {}++ ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Float.asBool")+ return ReturnTuple(Box_Bool(value_ != 0.0));+ }++ ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Float.asFloat")+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Float.asInt")+ return ReturnTuple(Box_Int(value_));+ }++ ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Float.formatted")+ std::ostringstream output;+ output << value_;+ return ReturnTuple(Box_String(output.str()));+ }++ PrimFloat AsFloat() const final { return value_; }++ const PrimFloat value_;+};++Category_Float& CreateCategory_Float() {+ static auto& category = *new ExtCategory_Float();+ return category;+}+S<Type_Float> CreateType_Float(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_Float(CreateCategory_Float(), Params<0>::Type()));+ return cached;+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE++S<TypeValue> Box_Float(PrimFloat value) {+ return S_get(new ExtValue_Float(CreateType_Float(Params<0>::Type()), value));+}
+ base/src/Extension_Int.cpp view
@@ -0,0 +1,118 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include <sstream>++#include "category-source.hpp"+#include "Streamlined_Int.hpp"+#include "Category_AsBool.hpp"+#include "Category_AsChar.hpp"+#include "Category_AsFloat.hpp"+#include "Category_AsInt.hpp"+#include "Category_Bool.hpp"+#include "Category_Char.hpp"+#include "Category_Default.hpp"+#include "Category_Equals.hpp"+#include "Category_Float.hpp"+#include "Category_Formatted.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_String.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_Int : public Category_Int {+};++struct ExtType_Int : public Type_Int {+ inline ExtType_Int(Category_Int& p, Params<0>::Type params) : Type_Int(p, params) {}++ ReturnTuple Call_default(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.default")+ return ReturnTuple(Box_Int(0));+ }++ ReturnTuple Call_equals(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.equals")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ const PrimInt Var_arg2 = (args.At(1))->AsInt();+ return ReturnTuple(Box_Bool(Var_arg1==Var_arg2));+ }++ ReturnTuple Call_lessThan(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.lessThan")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ const PrimInt Var_arg2 = (args.At(1))->AsInt();+ return ReturnTuple(Box_Bool(Var_arg1<Var_arg2));+ }+};++struct ExtValue_Int : public Value_Int {+ inline ExtValue_Int(S<Type_Int> p, PrimInt value) : Value_Int(p), value_(value) {}++ ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.asBool")+ return ReturnTuple(Box_Bool(value_ != 0));+ }++ ReturnTuple Call_asChar(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.asChar")+ return ReturnTuple(Box_Char(value_ % 0xff));+ }++ ReturnTuple Call_asFloat(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.asFloat")+ return ReturnTuple(Box_Float(value_));+ }++ ReturnTuple Call_asInt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.asInt")+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("Int.formatted")+ std::ostringstream output;+ output << value_;+ return ReturnTuple(Box_String(output.str()));+ }++ PrimInt AsInt() const final { return value_; }++ const PrimInt value_;+};++Category_Int& CreateCategory_Int() {+ static auto& category = *new ExtCategory_Int();+ return category;+}+S<Type_Int> CreateType_Int(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_Int(CreateCategory_Int(), Params<0>::Type()));+ return cached;+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE++S<TypeValue> Box_Int(PrimInt value) {+ return S_get(new ExtValue_Int(CreateType_Int(Params<0>::Type()), value));+}
+ base/src/Extension_String.cpp view
@@ -0,0 +1,204 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"+#include "Streamlined_String.hpp"+#include "Category_Append.hpp"+#include "Category_AsBool.hpp"+#include "Category_Bool.hpp"+#include "Category_Build.hpp"+#include "Category_Char.hpp"+#include "Category_CharBuffer.hpp"+#include "Category_Container.hpp"+#include "Category_Default.hpp"+#include "Category_DefaultOrder.hpp"+#include "Category_Equals.hpp"+#include "Category_Formatted.hpp"+#include "Category_Int.hpp"+#include "Category_LessThan.hpp"+#include "Category_Order.hpp"+#include "Category_ReadAt.hpp"+#include "Category_String.hpp"+#include "Category_SubSequence.hpp"++#ifdef ZEOLITE_PUBLIC_NAMESPACE+namespace ZEOLITE_PUBLIC_NAMESPACE {+#endif // ZEOLITE_PUBLIC_NAMESPACE++struct ExtCategory_String : public Category_String {+};++class Value_StringBuilder : public TypeValue {+ public:+ std::string CategoryName() const final { return "StringBuilder"; }++ ReturnTuple Dispatch(const S<TypeValue>& self,+ const ValueFunction& label,+ const ParamTuple& params, const ValueTuple& args) final {+ if (args.Size() != label.arg_count) {+ FAIL() << "Wrong number of args";+ }+ if (params.Size() != label.param_count){+ FAIL() << "Wrong number of params";+ }+ if (&label == &Function_Append_append) {+ TRACE_FUNCTION("StringBuilder.append")+ std::lock_guard<std::mutex> lock(mutex);+ output_ << args.At(0)->AsString();+ return ReturnTuple(self);+ }+ if (&label == &Function_Build_build) {+ TRACE_FUNCTION("StringBuilder.build")+ std::lock_guard<std::mutex> lock(mutex);+ return ReturnTuple(Box_String(output_.str()));+ }+ return TypeValue::Dispatch(self, label, params, args);+ }++ private:+ std::mutex mutex;+ std::ostringstream output_;+};++struct ExtType_String : public Type_String {+ inline ExtType_String(Category_String& p, Params<0>::Type params) : Type_String(p, params) {}++ ReturnTuple Call_builder(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.builder")+ return ReturnTuple(S<TypeValue>(new Value_StringBuilder));+ }++ ReturnTuple Call_default(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.default")+ return ReturnTuple(Box_String(""));+ }++ ReturnTuple Call_equals(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.equals")+ const S<TypeValue>& Var_arg1 = (args.At(0));+ const S<TypeValue>& Var_arg2 = (args.At(1));+ return ReturnTuple(Box_Bool(Var_arg1->AsString()==Var_arg2->AsString()));+ }++ ReturnTuple Call_fromCharBuffer(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.fromCharBuffer")+ const S<TypeValue>& Var_arg1 = (args.At(0));+ return ReturnTuple(Box_String(PrimString(Var_arg1->AsCharBuffer())));+ }++ ReturnTuple Call_lessThan(const S<TypeInstance>& Param_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.lessThan")+ const S<TypeValue>& Var_arg1 = (args.At(0));+ const S<TypeValue>& Var_arg2 = (args.At(1));+ return ReturnTuple(Box_Bool(Var_arg1->AsString()<Var_arg2->AsString()));+ }+};++struct StringOrder : public AnonymousOrder {+ StringOrder(S<TypeValue> container, const std::string& s)+ : AnonymousOrder(container, Function_Order_next, Function_Order_get), value(s) {}++ S<TypeValue> Call_next(const S<TypeValue>& self) final {+ if (index+1 >= value.size()) {+ return Var_empty;+ } else {+ ++index;+ return self;+ }+ }++ S<TypeValue> Call_get(const S<TypeValue>& self) final {+ if (index >= value.size()) FAIL() << "Iterated past end of String";+ return Box_Char(value[index]);+ }++ const std::string& value;+ int index = 0;+};++struct ExtValue_String : public Value_String {+ inline ExtValue_String(S<Type_String> p, const PrimString& value) : Value_String(p), value_(value) {}++ ReturnTuple Call_asBool(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.asBool")+ return ReturnTuple(Box_Bool(value_.size() != 0));+ }++ ReturnTuple Call_defaultOrder(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.defaultOrder")+ if (value_.empty()) {+ return ReturnTuple(Var_empty);+ } else {+ return ReturnTuple(S_get(new StringOrder(Var_self, value_)));+ }+ }++ ReturnTuple Call_formatted(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.formatted")+ return ReturnTuple(Var_self);+ }++ ReturnTuple Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.readAt")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ if (Var_arg1 < 0 || Var_arg1 >= value_.size()) {+ FAIL() << "Read position " << Var_arg1 << " is out of bounds";+ }+ return ReturnTuple(Box_Char(value_[Var_arg1]));+ }++ ReturnTuple Call_size(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.size")+ return ReturnTuple(Box_Int(value_.size()));+ }++ ReturnTuple Call_subSequence(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final {+ TRACE_FUNCTION("String.subSequence")+ const PrimInt Var_arg1 = (args.At(0))->AsInt();+ const PrimInt Var_arg2 = (args.At(1))->AsInt();+ if (Var_arg1 < 0 || Var_arg1 > value_.size()) {+ FAIL() << "Subsequence position " << Var_arg1 << " is out of bounds";+ }+ if (Var_arg2 < 0 || Var_arg1 + Var_arg2 > value_.size()) {+ FAIL() << "Subsequence size " << Var_arg2 << " is invalid";+ }+ return ReturnTuple(Box_String(value_.substr(Var_arg1,Var_arg2)));+ }++ const PrimString& AsString() const final { return value_; }++ const PrimString value_;+};++Category_String& CreateCategory_String() {+ static auto& category = *new ExtCategory_String();+ return category;+}+S<Type_String> CreateType_String(Params<0>::Type params) {+ static const auto cached = S_get(new ExtType_String(CreateCategory_String(), Params<0>::Type()));+ return cached;+}++#ifdef ZEOLITE_PUBLIC_NAMESPACE+} // namespace ZEOLITE_PUBLIC_NAMESPACE+using namespace ZEOLITE_PUBLIC_NAMESPACE;+#endif // ZEOLITE_PUBLIC_NAMESPACE++S<TypeValue> Box_String(const PrimString& value) {+ return S_get(new ExtValue_String(CreateType_String(Params<0>::Type()), value));+}
+ base/src/category-source.cpp view
@@ -0,0 +1,297 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "category-source.hpp"++#include <algorithm>++#include "logging.hpp"+++namespace {++struct OptionalEmpty : public TypeValue {+ ReturnTuple Dispatch(const S<TypeValue>& self,+ const ValueFunction& label,+ const ParamTuple& params, const ValueTuple& args) final {+ FAIL() << "Function called on empty value";+ __builtin_unreachable();+ }++ std::string CategoryName() const final { return "empty"; }++ bool Present() const final { return false; }+};++struct Type_Intersect : public TypeInstance {+ Type_Intersect(L<S<const TypeInstance>> params) : params_(params.begin(), params.end()) {}++ std::string CategoryName() const final { return "(intersection)"; }++ void BuildTypeName(std::ostream& output) const final {+ if (params_.empty()) {+ output << "any";+ } else {+ output << "[";+ bool first = true;+ for (const auto param : params_) {+ if (!first) output << "&";+ first = false;+ param->BuildTypeName(output);+ }+ output << "]";+ }+ }++ MergeType InstanceMergeType() const final+ { return MergeType::INTERSECT; }++ std::vector<S<const TypeInstance>> MergedTypes() const final+ { return params_; }++ const L<S<const TypeInstance>> params_;+};++struct Type_Union : public TypeInstance {+ Type_Union(L<S<const TypeInstance>> params) : params_(params.begin(), params.end()) {}++ std::string CategoryName() const final { return "(union)"; }++ void BuildTypeName(std::ostream& output) const final {+ if (params_.empty()) {+ output << "all";+ } else {+ output << "[";+ bool first = true;+ for (const auto param : params_) {+ if (!first) output << "|";+ first = false;+ param->BuildTypeName(output);+ }+ output << "]";+ }+ }++ MergeType InstanceMergeType() const final+ { return MergeType::UNION; }++ std::vector<S<const TypeInstance>> MergedTypes() const final+ { return params_; }++ const L<S<const TypeInstance>> params_;+};++L<const TypeInstance*> ParamsToKey(const L<S<const TypeInstance>>& params) {+ L<const TypeInstance*> key;+ for (const auto& param : params) {+ key.push_back(param.get());+ }+ std::sort(key.begin(), key.end());+ return key;+}++} // namespace+++S<TypeInstance> Merge_Intersect(L<S<const TypeInstance>> params) {+ static auto& cache = *new std::map<L<const TypeInstance*>,S<Type_Intersect>>();+ auto& cached = cache[ParamsToKey(params)];+ S<Type_Intersect> type = cached;+ if (!type) { cached = type = S_get(new Type_Intersect(params)); }+ return type;+}++S<TypeInstance> Merge_Union(L<S<const TypeInstance>> params) {+ static auto& cache = *new std::map<L<const TypeInstance*>,S<Type_Union>>();+ auto& cached = cache[ParamsToKey(params)];+ S<Type_Union> type = cached;+ if (!type) { cached = type = S_get(new Type_Union(params)); }+ return type;+}++const S<TypeInstance>& GetMerged_Any() {+ static const auto instance = Merge_Intersect(L_get<S<const TypeInstance>>());+ return instance;+}++const S<TypeInstance>& GetMerged_All() {+ static const auto instance = Merge_Union(L_get<S<const TypeInstance>>());+ return instance;+}+++const S<TypeValue>& Var_empty = *new S<TypeValue>(new OptionalEmpty());+++ReturnTuple TypeCategory::Dispatch(const CategoryFunction& label,+ const ParamTuple& params, const ValueTuple& args) {+ FAIL() << CategoryName() << " does not implement " << label;+ __builtin_unreachable();+}++ReturnTuple TypeInstance::Dispatch(const S<TypeInstance>& self, const TypeFunction& label,+ const ParamTuple& params, const ValueTuple& args) {+ FAIL() << CategoryName() << " does not implement " << label;+ __builtin_unreachable();+}++ReturnTuple TypeValue::Dispatch(const S<TypeValue>& self, const ValueFunction& label,+ const ParamTuple& params, const ValueTuple& args) {+ FAIL() << CategoryName() << " does not implement " << label;+ __builtin_unreachable();+}++bool TypeInstance::CanConvert(const S<const TypeInstance>& x,+ const S<const TypeInstance>& y) {+ // See pairMergeTree for the ordering here.+ // TODO: Consider using a cache here, since the check could be expensive.+ if (x.get() == y.get()) {+ return true;+ } else if (x->InstanceMergeType() == MergeType::INTERSECT &&+ y->InstanceMergeType() == MergeType::UNION) {+ for (const auto& left : x->MergedTypes()) {+ if (left->InstanceMergeType() == MergeType::SINGLE) {+ for (const auto& right : y->MergedTypes()) {+ if (right->InstanceMergeType() == MergeType::SINGLE) {+ if (TypeInstance::CanConvert(left, right)) {+ return true;+ }+ }+ }+ }+ }+ for (const auto& left : x->MergedTypes()) {+ if (TypeInstance::CanConvert(left, y)) {+ return true;+ }+ }+ for (const auto right : y->MergedTypes()) {+ if (TypeInstance::CanConvert(x, right)) {+ return true;+ }+ }+ return false;+ } else if (y->InstanceMergeType() == MergeType::INTERSECT) {+ for (const auto& right : y->MergedTypes()) {+ if (!TypeInstance::CanConvert(x, right)) {+ return false;+ }+ }+ return true;+ } else if (x->InstanceMergeType() == MergeType::UNION) {+ for (const auto& left : x->MergedTypes()) {+ if (!TypeInstance::CanConvert(left, y)) {+ return false;+ }+ }+ return true;+ } else if (x->InstanceMergeType() == MergeType::INTERSECT) {+ for (const auto& left : x->MergedTypes()) {+ if (TypeInstance::CanConvert(left, y)) {+ return true;+ }+ }+ return false;+ } else if (y->InstanceMergeType() == MergeType::UNION) {+ for (const auto right : y->MergedTypes()) {+ if (TypeInstance::CanConvert(x, right)) {+ return true;+ }+ }+ return false;+ } else {+ return y->CanConvertFrom(x);+ }+}++bool TypeValue::Present(S<TypeValue> target) {+ if (target == nullptr) {+ FAIL() << "Builtin called on null value";+ }+ return target->Present();+}++S<TypeValue> TypeValue::Require(S<TypeValue> target) {+ if (target == nullptr) {+ FAIL() << "Builtin called on null value";+ }+ if (!target->Present()) {+ FAIL() << "Cannot require empty value";+ }+ return target;+}++S<TypeValue> TypeValue::Strong(W<TypeValue> target) {+ const auto strong = target.lock();+ return strong? strong : Var_empty;+}++bool TypeValue::AsBool() const {+ FAIL() << CategoryName() << " is not a Bool value";+ __builtin_unreachable();+}++const PrimString& TypeValue::AsString() const {+ FAIL() << CategoryName() << " is not a String value";+ __builtin_unreachable();+}++PrimChar TypeValue::AsChar() const {+ FAIL() << CategoryName() << " is not a Char value";+ __builtin_unreachable();+}++PrimCharBuffer& TypeValue::AsCharBuffer() {+ FAIL() << CategoryName() << " is not a CharBuffer value";+ __builtin_unreachable();+}++PrimInt TypeValue::AsInt() const {+ FAIL() << CategoryName() << " is not an Int value";+ __builtin_unreachable();+}++PrimFloat TypeValue::AsFloat() const {+ FAIL() << CategoryName() << " is not a Float value";+ __builtin_unreachable();+}++bool TypeValue::Present() const {+ return true;+}++AnonymousOrder::AnonymousOrder(const S<TypeValue> cont,+ const ValueFunction& func_next,+ const ValueFunction& func_get)+ : container(cont), function_next(func_next), function_get(func_get) {}++std::string AnonymousOrder::CategoryName() const { return "AnonymousOrder"; }++ReturnTuple AnonymousOrder::Dispatch(+ const S<TypeValue>& self, const ValueFunction& label,+ const ParamTuple& params, const ValueTuple& args) {+ if (&label == &function_next) {+ TRACE_FUNCTION("AnonymousOrder.next")+ return ReturnTuple(Call_next(self));+ }+ if (&label == &function_get) {+ TRACE_FUNCTION("AnonymousOrder.get")+ return ReturnTuple(Call_get(self));+ }+ return TypeValue::Dispatch(self, label, params, args);+}
+ base/src/logging.cpp view
@@ -0,0 +1,234 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2020 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "logging.hpp"++#include <cassert>+#include <chrono>+#include <csignal>+#include <iomanip>+#include <iostream>+++LogThenCrash::LogThenCrash(bool fail, const std::string& condition)+ : fail_(fail), signal_(SIGABRT), condition_(condition) {}++LogThenCrash::LogThenCrash(bool fail, int signal)+ : fail_(fail), signal_(signal) {}++LogThenCrash::~LogThenCrash() {+ if (fail_) {+ std::signal(signal_, SIG_DFL);+ if (Argv::ArgCount() > 0) {+ std::cerr << Argv::GetArgAt(0) << ": ";+ }+ std::cerr << "Failed condition";+ if (!condition_.empty()) {+ std::cerr << " '" << condition_ << "'";+ }+ std::cerr << ": " << output_.str() << std::endl;+ PrintTrace(TraceContext::GetTrace());+ const TraceList creation_trace = TraceCreation::GetTrace();+ if (!creation_trace.empty()) {+ std::cerr << TraceCreation::GetType() << " value originally created at:" << std::endl;+ PrintTrace(creation_trace);+ }+ std::raise(signal_);+ }+}++// static+void LogThenCrash::PrintTrace(const TraceList &call_trace) {+ for (const auto& trace : call_trace) {+ const std::string message = trace();+ if (!message.empty()) {+ std::cerr << " " << message << std::endl;+ }+ }+}++// TODO: Should only be available used if POSIX is defined.+void TraceOnSignal(int signal) {+ LogThenCrash(true,signal) << "Recieved signal " << signal;+}++// TODO: Should only be available used if POSIX is defined.+void SetSignalHandler() {+#ifdef SIGINT+ std::signal(SIGINT, &TraceOnSignal);+#endif+#ifdef SIGILL+ std::signal(SIGILL, &TraceOnSignal);+#endif+#ifdef SIGABRT+ std::signal(SIGABRT, &TraceOnSignal);+#endif+#ifdef SIGFPE+ std::signal(SIGFPE, &TraceOnSignal);+#endif+#ifdef SIGQUIT+ std::signal(SIGQUIT, &TraceOnSignal);+#endif+#ifdef SIGSEGV+ std::signal(SIGSEGV, &TraceOnSignal);+#endif+#ifdef SIGPIPE+ std::signal(SIGPIPE, &TraceOnSignal);+#endif+#ifdef SIGALRM+ std::signal(SIGALRM, &TraceOnSignal);+#endif+#ifdef SIGTERM+ std::signal(SIGTERM, &TraceOnSignal);+#endif+#ifdef SIGUSR1+ std::signal(SIGUSR1, &TraceOnSignal);+#endif+#ifdef SIGUSR2+ std::signal(SIGUSR2, &TraceOnSignal);+#endif+}+++TraceList TraceContext::GetTrace() {+ TraceList trace;+ const TraceContext* current = GetCurrent();+ while (current) {+ current->AppendTrace(trace);+ current = current->GetNext();+ }+ return trace;+}+++void SourceContext::SetLocal(const char* at) {+ at_ = at;+ LogCalls::MaybeLogCall(name_, at_);+}++void SourceContext::AppendTrace(TraceList& trace) const {+ const char* const name = name_;+ const char* const at = at_;+ trace.push_back([name,at]() {+ std::ostringstream output;+ if (at == nullptr || at[0] == 0x00) {+ output << "From " << name;+ } else {+ output << "From " << name << " at " << at;+ }+ return output.str();+ });+}++const TraceContext* SourceContext::GetNext() const {+ return capture_to_.Previous();+}+++void CleanupContext::SetLocal(const char* at) {+ at_ = at;+}++void CleanupContext::AppendTrace(TraceList& trace) const {+ const char* const at = at_;+ trace.push_back([at]() {+ std::ostringstream output;+ if (at == nullptr || at[0] == 0x00) {+ output << "In cleanup block";+ } else {+ output << "In cleanup block at " << at;+ }+ return output.str();+ });+}++const TraceContext* CleanupContext::GetNext() const {+ return capture_to_.Previous();+}++int Argv::ArgCount() {+ if (GetCurrent()) {+ return GetCurrent()->GetArgs().size();+ } else {+ return 0;+ }+}++const std::string& Argv::GetArgAt(int pos) {+ if (pos < 0 || pos >= ArgCount()) {+ FAIL() << "Argv index " << pos << " is out of bounds";+ __builtin_unreachable();+ } else {+ return GetCurrent()->GetArgs()[pos];+ }+}++const std::vector<std::string>& ProgramArgv::GetArgs() const {+ return argv_;+}++std::string FixCsvString(const char* string) {+ std::string fixed;+ while (*string) {+ switch (*string) {+ case '\\':+ break;+ case '"':+ fixed.push_back('\'');+ break;+ default:+ fixed.push_back(*string);+ break;+ }+ ++string;+ }+ return fixed;+}++unsigned int UniqueId() {+ const auto time = std::chrono::steady_clock::now().time_since_epoch();+ return (1000000009 * std::chrono::duration_cast<std::chrono::microseconds>(time).count());+}++LogCallsToFile::LogCallsToFile(std::string filename)+ : unique_id_(UniqueId()),+ filename_(std::move(filename)),+ log_file_(filename_.empty()?+ nullptr :+ new std::fstream(filename_, std::ios::in |+ std::ios::out |+ std::ios::ate |+ std::ios::app)),+ cross_and_capture_to_(this) {+ if (log_file_) {+ if (!*log_file_) {+ FAIL() << "Failed to open call log " << filename_ << " for writing";+ }+ }+}++void LogCallsToFile::LogCall(const char* name, const char* at) {+ if (log_file_) {+ std::lock_guard<std::mutex> lock(mutex_);+ const auto time = std::chrono::steady_clock::now().time_since_epoch();+ *log_file_ << std::chrono::duration_cast<std::chrono::microseconds>(time).count() << ","+ << unique_id_ << ","+ << "\"" << FixCsvString(name) << "\"" << ","+ << "\"" << FixCsvString(at) << "\"" << std::endl;+ }+}
+ base/src/thread-crosser.cc view
@@ -0,0 +1,33 @@+/* -----------------------------------------------------------------------------+Copyright 2017 Google Inc.++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com] [kevinbarry@google.com]++#include "thread-crosser.h"++namespace capture_thread {++namespace {+thread_local ThreadCrosser* current(nullptr);+}++// static+ThreadCrosser* ThreadCrosser::GetCurrent() { return current; }++// static+void ThreadCrosser::SetCurrent(ThreadCrosser* value) { current = value; }++} // namespace capture_thread
+ base/src/types.cpp view
@@ -0,0 +1,259 @@+/* -----------------------------------------------------------------------------+Copyright 2019,2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++#include "types.hpp"++#include <atomic>++#include "logging.hpp"+++int ArgTuple::Size() const {+ return size_;+}++const S<TypeValue>& ArgTuple::At(int pos) const {+ if (pos < 0 || pos >= size_) {+ FAIL() << "Bad ArgTuple index";+ }+ return *data_[pos];+}++const S<TypeValue>& ArgTuple::Only() const {+ if (size_ != 1) {+ FAIL() << "Bad ArgTuple index";+ }+ return *data_[0];+}++ReturnTuple& ReturnTuple::operator = (ReturnTuple&& other) {+ if (Size() != other.Size()) {+ FAIL() << "ReturnTuple size mismatch in assignment: " << Size()+ << " (expected) " << other.Size() << " (actual)";+ }+ for (int i = 0; i < Size(); ++i) {+ At(i) = std::move(other.At(i));+ }+ return *this;+}++int ReturnTuple::Size() const {+ return size_;+}++S<TypeValue>& ReturnTuple::At(int pos) {+ if (pos < 0 || pos >= size_) {+ FAIL() << "Bad ReturnTuple index";+ }+ return data_[pos];+}++const S<TypeValue>& ReturnTuple::At(int pos) const {+ if (pos < 0 || pos >= size_) {+ FAIL() << "Bad ReturnTuple index";+ }+ return data_[pos];+}++const S<TypeValue>& ReturnTuple::Only() const {+ if (size_ != 1) {+ FAIL() << "Bad ReturnTuple index";+ }+ return data_[0];+}++int ParamTuple::Size() const {+ return size_;+}++const S<TypeInstance>& ParamTuple::At(int pos) const {+ if (pos < 0 || pos >= size_) {+ FAIL() << "Bad ParamTuple index";+ }+ return data_[pos];+}+++template<class T>+class PoolCleanup {+ public:+ constexpr PoolCleanup() {}++ ~PoolCleanup() {+ PoolManager<T>::Purge();+ }++ private:+ PoolCleanup(const PoolCleanup&) = delete;+ PoolCleanup operator = (const PoolCleanup&) = delete;+ PoolCleanup(PoolCleanup&&) = delete;+ PoolCleanup operator = (PoolCleanup&&) = delete;+};+++static void* const pool_busy_flag_ = (void*) ~0x00;+++static unsigned int return_tuple_pool4_size_ = 0;+static std::atomic<PoolStorage<S<TypeValue>>*> return_tuple_pool4_{nullptr};++// static+PoolStorage<S<TypeValue>>* PoolManager<S<TypeValue>>::Take(int size) {+ if (size == 0) return nullptr;+ if (size < 4) {+ size = 4;+ }+ if (size == 4) {+ PoolEntry* storage = nullptr;+ while ((storage = return_tuple_pool4_.exchange((PoolEntry*) pool_busy_flag_)) == pool_busy_flag_);+ if (storage == nullptr) {+ return_tuple_pool4_.exchange(nullptr);+ } else {+ --return_tuple_pool4_size_;+ return_tuple_pool4_.exchange(storage->next);+ storage->next = nullptr;+ new (storage->data()) Managed[storage->size];+ return storage;+ }+ }+ PoolEntry* const storage = new (new unsigned char[sizeof(PoolEntry) + size*sizeof(Managed)]) PoolEntry(size, nullptr);+ new (storage->data()) Managed[size];+ return storage;+}++// static+void PoolManager<S<TypeValue>>::Return(PoolEntry* storage) {+ if (!storage) return;+ for (int i = 0; i < storage->size; ++i) {+ storage->data()[i].~Managed();+ }+ if (storage->size == 4) {+ PoolEntry* head = nullptr;+ while ((head = return_tuple_pool4_.exchange((PoolEntry*) pool_busy_flag_)) == pool_busy_flag_);+ if (return_tuple_pool4_size_ < pool_limit_) {+ ++return_tuple_pool4_size_;+ storage->next = head;+ return_tuple_pool4_.exchange(storage);+ return;+ } else {+ return_tuple_pool4_.exchange(head);+ }+ }+ storage->~PoolEntry();+ delete[] (unsigned char*) storage;+}+++static unsigned int arg_tuple_pool4_size_ = 0;+static std::atomic<PoolStorage<const S<TypeValue>*>*> arg_tuple_pool4_{nullptr};++// static+PoolStorage<const S<TypeValue>*>* PoolManager<const S<TypeValue>*>::Take(int size) {+ if (size == 0) return nullptr;+ if (size < 4) {+ size = 4;+ }+ if (size == 4) {+ PoolEntry* storage = nullptr;+ while ((storage = arg_tuple_pool4_.exchange((PoolEntry*) pool_busy_flag_)) == pool_busy_flag_);+ if (storage == nullptr) {+ arg_tuple_pool4_.exchange(nullptr);+ } else {+ --arg_tuple_pool4_size_;+ arg_tuple_pool4_.exchange(storage->next);+ storage->next = nullptr;+ new (storage->data()) Managed[storage->size];+ return storage;+ }+ }+ PoolEntry* const storage = new (new unsigned char[sizeof(PoolEntry) + size*sizeof(Managed)]) PoolEntry(size, nullptr);+ new (storage->data()) Managed[size];+ return storage;+}++// static+void PoolManager<const S<TypeValue>*>::Return(PoolEntry* storage) {+ if (!storage) return;+ for (int i = 0; i < storage->size; ++i) {+ storage->data()[i].~Managed();+ }+ if (storage->size == 4) {+ PoolEntry* head = nullptr;+ while ((head = arg_tuple_pool4_.exchange((PoolEntry*) pool_busy_flag_)) == pool_busy_flag_);+ if (arg_tuple_pool4_size_ < pool_limit_) {+ ++arg_tuple_pool4_size_;+ storage->next = head;+ arg_tuple_pool4_.exchange(storage);+ return;+ } else {+ arg_tuple_pool4_.exchange(head);+ }+ }+ storage->~PoolEntry();+ delete[] (unsigned char*) storage;+}+++static unsigned int param_tuple_pool4_size_ = 0;+static std::atomic<PoolStorage<S<TypeInstance>>*> param_tuple_pool4_{nullptr};++// static+PoolStorage<S<TypeInstance>>* PoolManager<S<TypeInstance>>::Take(int size) {+ if (size == 0) return nullptr;+ if (size < 4) {+ size = 4;+ }+ if (size == 4) {+ PoolEntry* storage = nullptr;+ while ((storage = param_tuple_pool4_.exchange((PoolEntry*) pool_busy_flag_)) == pool_busy_flag_);+ if (storage == nullptr) {+ param_tuple_pool4_.exchange(nullptr);+ } else {+ --param_tuple_pool4_size_;+ param_tuple_pool4_.exchange(storage->next);+ storage->next = nullptr;+ new (storage->data()) Managed[storage->size];+ return storage;+ }+ }+ PoolEntry* const storage = new (new unsigned char[sizeof(PoolEntry) + size*sizeof(Managed)]) PoolEntry(size, nullptr);+ new (storage->data()) Managed[size];+ return storage;+}++// static+void PoolManager<S<TypeInstance>>::Return(PoolEntry* storage) {+ if (!storage) return;+ for (int i = 0; i < storage->size; ++i) {+ storage->data()[i].~Managed();+ }+ if (storage->size == 4) {+ PoolEntry* head = nullptr;+ while ((head = param_tuple_pool4_.exchange((PoolEntry*) pool_busy_flag_)) == pool_busy_flag_);+ if (param_tuple_pool4_size_ < pool_limit_) {+ ++param_tuple_pool4_size_;+ storage->next = head;+ param_tuple_pool4_.exchange(storage);+ return;+ } else {+ param_tuple_pool4_.exchange(head);+ }+ }+ storage->~PoolEntry();+ delete[] (unsigned char*) storage;+}
− base/thread-crosser.cc
@@ -1,33 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2017 Google Inc.--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com] [kevinbarry@google.com]--#include "thread-crosser.h"--namespace capture_thread {--namespace {-thread_local ThreadCrosser* current(nullptr);-}--// static-ThreadCrosser* ThreadCrosser::GetCurrent() { return current; }--// static-void ThreadCrosser::SetCurrent(ThreadCrosser* value) { current = value; }--} // namespace capture_thread
− base/types.cpp
@@ -1,87 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2019 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--#include "types.hpp"--#include "logging.hpp"---int ArgTuple::Size() const {- return args_.size();-}--const S<TypeValue>& ArgTuple::At(int pos) const {- if (pos < 0 || pos >= args_.size()) {- FAIL() << "Bad ArgTuple index";- }- return *args_[pos];-}--const S<TypeValue>& ArgTuple::Only() const {- if (args_.size() != 1) {- FAIL() << "Bad ArgTuple index";- }- return *args_[0];-}--ReturnTuple& ReturnTuple::operator =(ReturnTuple &&other) {- if (Size() != other.Size()) {- FAIL() << "ReturnTuple size mismatch in assignment: " << Size()- << " (expected) " << other.Size() << " (actual)";- }- for (int i = 0; i < Size(); ++i) {- At(i) = std::move(other.At(i));- }- return *this;-}--int ReturnTuple::Size() const {- return returns_.size();-}--S<TypeValue>& ReturnTuple::At(int pos) {- if (pos < 0 || pos >= returns_.size()) {- FAIL() << "Bad ReturnTuple index";- }- return returns_[pos];-}--const S<TypeValue>& ReturnTuple::At(int pos) const {- if (pos < 0 || pos >= returns_.size()) {- FAIL() << "Bad ReturnTuple index";- }- return returns_[pos];-}--const S<TypeValue>& ReturnTuple::Only() const {- if (returns_.size() != 1) {- FAIL() << "Bad ReturnTuple index";- }- return returns_[0];-}--int ParamTuple::Size() const {- return params_.size();-}--const S<TypeInstance>& ParamTuple::At(int pos) const {- if (pos < 0 || pos >= params_.size()) {- FAIL() << "Bad ParamTuple index";- }- return params_[pos];-}
base/types.hpp view
@@ -1,5 +1,5 @@ /* ------------------------------------------------------------------------------Copyright 2019-2020 Kevin P. Barry+Copyright 2019-2021 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.@@ -26,6 +26,7 @@ #include <vector> #include "logging.hpp"+#include "pooled.hpp" #define ALWAYS_PERMANENT(type) \@@ -34,9 +35,12 @@ type& operator =(const type&) = delete; \ type& operator =(type&&) = delete; +using CollectionType = int;+ using PrimInt = std::int64_t; using PrimString = std::string; using PrimChar = char;+using PrimCharBuffer = std::string; using PrimFloat = double; template<int S>@@ -172,16 +176,31 @@ void* operator new(std::size_t size) = delete; }; +template<>+class PoolManager<S<TypeValue>> {+ using Managed = S<TypeValue>;+ using PoolEntry = PoolStorage<Managed>;++ template<class> friend class PoolArray;++ static PoolEntry* Take(int size);+ static void Return(PoolEntry* storage);++ static constexpr unsigned int pool_limit_ = 256;+};+ class ReturnTuple : public ValueTuple { public:- ReturnTuple(int size) : returns_(size) {}-- ReturnTuple(ReturnTuple&&) = default;- ReturnTuple& operator =(ReturnTuple&&);+ ReturnTuple(int size) : size_(size), data_(size_) {} template<class...Ts>- explicit ReturnTuple(Ts... returns) : returns_{std::move(returns)...} {}+ explicit ReturnTuple(Ts... returns) : size_(sizeof...(Ts)), data_(size_) {+ data_.Init(std::move(returns)...);+ } + ReturnTuple(ReturnTuple&&) = default;+ ReturnTuple& operator = (ReturnTuple&&);+ int Size() const final; S<TypeValue>& At(int pos); const S<TypeValue>& At(int pos) const final;@@ -190,14 +209,31 @@ private: ReturnTuple(const ReturnTuple&) = delete; ReturnTuple& operator =(const ReturnTuple&) = delete;+ void* operator new(std::size_t size) = delete; - std::vector<S<TypeValue>> returns_;+ int size_;+ PoolArray<S<TypeValue>> data_; }; +template<>+class PoolManager<const S<TypeValue>*> {+ using Managed = const S<TypeValue>*;+ using PoolEntry = PoolStorage<Managed>;++ template<class> friend class PoolArray;++ static PoolEntry* Take(int size);+ static void Return(PoolEntry* storage);++ static constexpr unsigned int pool_limit_ = 256;+};+ class ArgTuple : public ValueTuple { public: template<class...Ts>- explicit ArgTuple(const Ts&... args) : args_{&args...} {}+ explicit ArgTuple(const Ts&... args) : size_(sizeof...(Ts)), data_(size_) {+ data_.Init(&args...);+ } int Size() const final; const S<TypeValue>& At(int pos) const final;@@ -206,28 +242,47 @@ private: ArgTuple(const ArgTuple&) = delete; ArgTuple(ArgTuple&&) = delete;- ArgTuple& operator =(const ArgTuple&) = delete;- ArgTuple& operator =(ArgTuple&&) = delete;+ ArgTuple& operator = (const ArgTuple&) = delete;+ ArgTuple& operator = (ArgTuple&&) = delete;+ void* operator new(std::size_t size) = delete; - std::vector<const S<TypeValue>*> args_;+ int size_;+ PoolArray<const S<TypeValue>*> data_; }; +template<>+class PoolManager<S<TypeInstance>> {+ using Managed = S<TypeInstance>;+ using PoolEntry = PoolStorage<Managed>;++ template<class> friend class PoolArray;++ static PoolEntry* Take(int size);+ static void Return(PoolEntry* storage);++ static constexpr unsigned int pool_limit_ = 256;+};+ class ParamTuple { public:- ParamTuple(ParamTuple&& other) : params_(std::move(other.params_)) {}- template<class...Ts>- explicit ParamTuple(const Ts&... args) : params_{args...} {}+ explicit ParamTuple(const Ts&... params) : size_(sizeof...(Ts)), data_(size_) {+ data_.Init(std::move(params)...);+ } + ParamTuple(ParamTuple&& other) = default;+ int Size() const; const S<TypeInstance>& At(int pos) const; private: ParamTuple(const ParamTuple&) = delete;- ParamTuple& operator =(const ParamTuple&) = delete;+ ParamTuple& operator = (const ParamTuple&) = delete;+ ParamTuple& operator = (ParamTuple&&) = delete; void* operator new(std::size_t size) = delete; - std::vector<S<TypeInstance>> params_;+ int size_;+ PoolArray<S<TypeInstance>> data_; }; inline ReturnTuple FailWhenNull(ReturnTuple values) {
example/parser/parse-text.0rp view
@@ -1,23 +1,19 @@-/* Parses a fixed string.- */+// Parses a fixed string. concrete StringParser { @type create (String) -> (Parser<String>) } -/* Parses a string containing a limited set of characters.- */+// Parses a string containing a limited set of characters. concrete SequenceOfParser { @type create (String, Int /*min*/, Int /*max*/) -> (Parser<String>) } -/* Parses a fixed character.- */+// Parses a fixed character. concrete CharParser { @type create (Char) -> (Parser<Char>) } -/* Parser combinators.- */+// Parser combinators. concrete Parse { @type const<#x> (#x) -> (Parser<#x>) @type error (Formatted) -> (Parser<all>)
example/parser/parser.0rp view
@@ -1,29 +1,26 @@-/* Manages state for parsing operations outside of a Parser.- *- * The state is immutable; all update operations return a new state.- *- * Since #x is covariant, any ParseState can convert to ParseState<any>, and- * ParseState<all> can convert to all other ParseState.- */+// Manages state for parsing operations outside of a Parser.+//+// The state is immutable; all update operations return a new state.+//+// Since #x is covariant, any ParseState can convert to ParseState<any>, and+// ParseState<all> can convert to all other ParseState. concrete ParseState<|#x> { // Consumes all input and returns the result. @category consumeAll<#y> (Parser<#y>,String) -> (ErrorOr<#y>) } -/* A self-contained parser operation.- *- * Since #x is covariant, any Parser can convert to Parser<any>, and Parser<all>- * can convert to all other Parser.- */+// A self-contained parser operation.+//+// Since #x is covariant, any Parser can convert to Parser<any>, and Parser<all>+// can convert to all other Parser. @value interface Parser<|#x> { run (ParseContext<any>) -> (ParseState<#x>) } -/* Parser context available when running a Parser.- *- * Since #x is covariant, any ParseContext can convert to ParseContext<any>, and- * ParseContext<all> can convert to all other ParseContext.- */+// Parser context available when running a Parser.+//+// Since #x is covariant, any ParseContext can convert to ParseContext<any>, and+// ParseContext<all> can convert to all other ParseContext. @value interface ParseContext<|#x> { // Continue computation. run<#y> (Parser<#y>) -> (ParseContext<#y>)
example/parser/test-data.0rp view
@@ -1,7 +1,6 @@ $TestsOnly$ -/* A contrived object for test data.- */+// A contrived object for test data. concrete TestData { @type create (String,String,Bool) -> (TestData) @@ -11,8 +10,7 @@ } -/* Parses the test-data.txt file using a one-off format.- */+// Parses the test-data.txt file using a one-off format. concrete TestDataParser { @type create () -> (Parser<TestData>) }
example/primes/flag.0rx view
@@ -12,8 +12,10 @@ MutexLock lock <- MutexLock.lock(cond) } cleanup { \ lock.freeResource()- } in enabled <- true- \ cond.resumeAll()+ } in {+ enabled <- true+ \ cond.resumeAll()+ } return self } @@ -39,8 +41,10 @@ MutexLock lock <- MutexLock.lock(cond) } cleanup { \ lock.freeResource()- } in canceled <- true- \ cond.resumeAll()+ } in {+ canceled <- true+ \ cond.resumeAll()+ } return self }
+ lib/container/auto-tree.0rp view
@@ -0,0 +1,141 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Provides basic balanced BST functionality to custom containers.+//+// Params:+// - #n: The type of node to be managed.+// - #k: The key type used by #n.+// - #v: The value type used by #n.+// - #r: A read-only subset of the functionality of #n.+//+// Notes:+// - This is not meant for direct use: It is only exposed in this library to+// allow other container authors to extend BST functionality by augmenting the+// data stored along with each node. This allows the augmented data to rely on+// where the node is within the tree.+// - #r should not expose any functionality of #n that can alter the integrity+// of the tree. It is provided as a filter for the return of getRoot() so that+// a container can implement custom functionality using the tree's structure+// without risking modification of the tree.+concrete AutoBinaryTree<|#n,#k,#v|#r> {+ refines Container+ #n defines KVFactory<#k,#v>+ #n requires BalancedTreeNode<#n,#k,#v>+ #k defines LessThan<#k>+ #r allows #n++ // Create a new tree.+ @type new () -> (#self)++ // Get the root of the tree.+ @value getRoot () -> (optional #r)++ // Get the value associated with the key.+ @value get (#k) -> (optional #v)++ // Set the value associated with the key.+ //+ // Notes:+ // - updateNode() will be called on every affected node, starting with the+ // deepest node. It might be called an arbitrary number of times per node.+ @value set (#k,#v) -> ()++ // Remove the node associated with the key.+ //+ // Notes:+ // - updateNode() will be called on every affected node, starting with the+ // deepest node. It might be called an arbitrary number of times per node.+ @value remove (#k) -> ()+}++// An interface for reading the state of a BST node.+//+// Notes:+// - This is intended for internal use in BST-based categories.+@value interface BinaryTreeNode<|#k,#v> {+ getLower () -> (optional #self)+ getHigher () -> (optional #self)+ getKey () -> (#k)+ getValue () -> (#v)+ getHeight () -> (Int)+}++// An interface for managing the state of a BST node.+//+// Notes:+// - This is intended for internal use in BST-based categories.+@value interface BalancedTreeNode<#n|#k,#v|> {+ refines BinaryTreeNode<#k,#v>++ // Set the lower child of the node.+ //+ // Notes:+ // - The key for the child is strictly less-than this node's key.+ // - updateNode() will be called separately to update the node's state.+ setLower (optional #n) -> ()++ // Set the higher child of the node.+ //+ // Notes:+ // - The key for the child is strictly greater-than this node's key.+ // - updateNode() will be called separately to update the node's state.+ setHigher (optional #n) -> ()++ // Set the value associated with the node.+ setValue (#v) -> ()++ // Update the state of the node, given its position in the tree.+ //+ // Notes:+ // - This should update the height of the subtree that starts with this node;+ // otherwise, the tree might not remain balanced.+ // - Also update any other node state that depends on the node's position+ // within the tree.+ // - This can be called an arbitrary number of times at any time; therefore,+ // it must always be idempotent.+ updateNode () -> ()+}++// Provides forward iteration of the nodes in a BST.+//+// Notes:+// - This is intended for internal use in BST-based categories.+concrete ForwardTreeOrder<|#k,#v> {+ refines Order<KeyValue<#k,#v>>++ @category create<#k,#v> (optional BinaryTreeNode<#k,#v>) -> (optional ForwardTreeOrder<#k,#v>)++ @category seek<#k,#v>+ #k defines LessThan<#k>+ (#k,optional BinaryTreeNode<#k,#v>) -> (optional ForwardTreeOrder<#k,#v>)+}++// Provides reverse iteration of the nodes in a BST.+//+// Notes:+// - This is intended for internal use in BST-based categories.+concrete ReverseTreeOrder<|#k,#v> {+ refines Order<KeyValue<#k,#v>>++ @category create<#k,#v> (optional BinaryTreeNode<#k,#v>) -> (optional ReverseTreeOrder<#k,#v>)++ @category seek<#k,#v>+ #k defines LessThan<#k>+ (#k,optional BinaryTreeNode<#k,#v>) -> (optional ReverseTreeOrder<#k,#v>)+}
+ lib/container/auto-tree.0rx view
@@ -0,0 +1,350 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define AutoBinaryTree {+ @value Int treeSize+ @value optional #n root++ new () {+ return #self{ 0, empty }+ }++ size () {+ return treeSize+ }++ getRoot () {+ return root+ }++ get (k) {+ return find(root,k)+ }++ set (k,v) {+ root, Bool added <- insert(root,k,v)+ if (added) {+ treeSize <- treeSize+1+ }+ }++ remove (k) {+ root, Bool removed <- delete(root,k)+ if (removed) {+ treeSize <- treeSize-1+ }+ }+++ @type insert (optional #n,#k,#v) -> (optional #n,Bool)+ insert (node,k,v) (newRoot,added) {+ if (!present(node)) {+ return #n.newNode(k,v), true+ }+ #n node2 <- require(node)+ if (k `#k.lessThan` node2.getKey()) {+ newRoot, added <- insert(node2.getLower(),k,v)+ \ node2.setLower(newRoot)+ newRoot <- rebalance(node2)+ } elif (node2.getKey() `#k.lessThan` k) {+ newRoot, added <- insert(node2.getHigher(),k,v)+ \ node2.setHigher(newRoot)+ newRoot <- rebalance(node2)+ } else {+ \ node2.setValue(v)+ \ node2.updateNode()+ return node2, false+ }+ }++ @type delete (optional #n,#k) -> (optional #n,Bool)+ delete (node,k) (newRoot,removed) {+ if (!present(node)) {+ return empty, false+ }+ #n node2 <- require(node)+ if (k `#k.lessThan` node2.getKey()) {+ newRoot, removed <- delete(node2.getLower(),k)+ \ node2.setLower(newRoot)+ newRoot <- rebalance(node2)+ } elif (node2.getKey() `#k.lessThan` k) {+ newRoot, removed <- delete(node2.getHigher(),k)+ \ node2.setHigher(newRoot)+ newRoot <- rebalance(node2)+ } else {+ return rebalance(removeNode(node2)), true+ }+ }++ @type find (optional #n,#k) -> (optional #v)+ find (node,k) {+ if (present(node)) {+ scoped {+ #n node2 <- require(node)+ } in if (k `#k.lessThan` node2.getKey()) {+ return find(node2.getLower(),k)+ } elif (node2.getKey() `#k.lessThan` k) {+ return find(node2.getHigher(),k)+ } else {+ return node2.getValue()+ }+ } else {+ return empty+ }+ }++ @type getBalance (optional #n) -> (Int)+ getBalance (node) (balance) {+ balance <- 0+ if (present(node)) {+ #n node2 <- require(node)+ if (present(node2.getLower())) {+ balance <- balance-require(node2.getLower()).getHeight()+ }+ if (present(node2.getHigher())) {+ balance <- balance+require(node2.getHigher()).getHeight()+ }+ }+ }++ @type rebalance (optional #n) -> (optional #n)+ rebalance (node) {+ if (!present(node)) {+ return empty+ }+ #n node2 <- require(node)+ \ node2.updateNode()+ scoped {+ Int balance <- getBalance(node2)+ } in if (balance > 1) {+ return pivotLower(node2)+ } elif (balance < -1) {+ return pivotHigher(node2)+ } else {+ return node2+ }+ }++ @type pivotHigher (#n) -> (#n)+ pivotHigher (node) (newNode) {+ if (getBalance(node.getLower()) > 0) {+ \ node.setLower(pivotLower(require(node.getLower())))+ }+ newNode <- require(node.getLower())+ \ node.setLower(newNode.getHigher())+ \ node.updateNode()+ \ newNode.setHigher(node)+ \ newNode.updateNode()+ }++ @type pivotLower (#n) -> (#n)+ pivotLower (node) (newNode) {+ if (getBalance(node.getHigher()) < 0) {+ \ node.setHigher(pivotHigher(require(node.getHigher())))+ }+ newNode <- require(node.getHigher())+ \ node.setHigher(newNode.getLower())+ \ node.updateNode()+ \ newNode.setLower(node)+ \ newNode.updateNode()+ }++ @type removeNode (#n) -> (optional #n)+ removeNode (node) (newNode) {+ if (getBalance(node) < 0) {+ optional #n temp, newNode <- removeHighest(node.getLower())+ \ node.setLower(temp)+ } else {+ optional #n temp, newNode <- removeLowest(node.getHigher())+ \ node.setHigher(temp)+ }+ if (present(newNode)) {+ \ swapChildren(node,require(newNode))+ \ require(newNode).updateNode()+ }+ }++ @type removeHighest (optional #n) -> (optional #n,optional #n)+ removeHighest (node) (newNode,removed) {+ if (!present(node)) {+ return empty, empty+ }+ #n node2 <- require(node)+ if (present(node2.getHigher())) {+ optional #n temp, removed <- removeHighest(node2.getHigher())+ \ node2.setHigher(temp)+ newNode <- rebalance(node2)+ } else {+ newNode <- node2.getLower()+ \ node2.setLower(empty)+ removed <- node+ }+ }++ @type removeLowest (optional #n) -> (optional #n,optional #n)+ removeLowest (node) (newNode,removed) {+ if (!present(node)) {+ return empty, empty+ }+ #n node2 <- require(node)+ if (present(node2.getLower())) {+ optional #n temp, removed <- removeLowest(node2.getLower())+ \ node2.setLower(temp)+ newNode <- rebalance(node2)+ } else {+ newNode <- node2.getHigher()+ \ node2.setHigher(empty)+ removed <- node+ }+ }++ @type swapChildren (#n,#n) -> ()+ swapChildren (l,r) {+ scoped {+ optional #n temp <- l.getLower()+ \ l.setLower(r.getLower())+ } in \ r.setLower(temp)+ scoped {+ optional #n temp <- l.getHigher()+ \ l.setHigher(r.getHigher())+ } in \ r.setHigher(temp)+ }+}++concrete TreeKeyValue<|#k,#v> {+ refines KeyValue<#k,#v>++ @category create<#k,#v> (#k,#v) -> (TreeKeyValue<#k,#v>)+}++define TreeKeyValue {+ $ReadOnly[key,value]$++ @value #k key+ @value #v value++ create (key,value) {+ return TreeKeyValue<#k,#v>{ key, value }+ }++ getKey () {+ return key+ }++ getValue () {+ return value+ }+}++define ForwardTreeOrder {+ $ReadOnly[node,prev]$++ @value BinaryTreeNode<#k,#v> node+ @value optional ForwardTreeOrder<#k,#v> prev++ create (node) (current) {+ optional BinaryTreeNode<#k,#v> node2 <- node+ current <- empty+ while (present(node2)) {+ current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getLower()+ }+ }++ seek (key,node) (current) {+ optional BinaryTreeNode<#k,#v> node2 <- node+ current <- empty+ while (present(node2)) {+ if (require(node2).getKey() `#k.lessThan` key) {+ // Skip node2 in the traversal, since it's before key.+ node2 <- require(node2).getHigher()+ } elif (key `#k.lessThan` require(node2).getKey()) {+ current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getLower()+ } else {+ current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ break+ }+ }+ }++ next () (current) {+ // Algorithm:+ // 1. Pop self from the stack.+ // 2. Traverse lower to the bottom starting from the higher child of self.+ optional BinaryTreeNode<#k,#v> node2 <- node.getHigher()+ current <- prev+ while (present(node2)) {+ current <- ForwardTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getLower()+ }+ }++ get () {+ return TreeKeyValue:create<?,?>(node.getKey(),node.getValue())+ }+}++define ReverseTreeOrder {+ $ReadOnly[node,prev]$++ @value BinaryTreeNode<#k,#v> node+ @value optional ReverseTreeOrder<#k,#v> prev++ create (node) (current) {+ optional BinaryTreeNode<#k,#v> node2 <- node+ current <- empty+ while (present(node2)) {+ current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getHigher()+ }+ }++ seek (key,node) (current) {+ optional BinaryTreeNode<#k,#v> node2 <- node+ current <- empty+ while (present(node2)) {+ if (require(node2).getKey() `#k.lessThan` key) {+ current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getHigher()+ } elif (key `#k.lessThan` require(node2).getKey()) {+ // Skip node2 in the traversal, since it's after key.+ node2 <- require(node2).getLower()+ } else {+ current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ break+ }+ }+ }++ next () (current) {+ // Algorithm:+ // 1. Pop self from the stack.+ // 2. Traverse higher to the bottom starting from the lower child of self.+ optional BinaryTreeNode<#k,#v> node2 <- node.getLower()+ current <- prev+ while (present(node2)) {+ current <- ReverseTreeOrder<#k,#v>{ require(node2), current }+ node2 <- require(node2).getHigher()+ }+ }++ get () {+ return TreeKeyValue:create<?,?>(node.getKey(),node.getValue())+ }+}
+ lib/container/helpers.0rp view
@@ -0,0 +1,88 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Helpers to extend functionality on keys and values to KeyValue.+concrete KeyValueH {+ // Compare for lessThan.+ //+ // Params:+ // - #k: Element type of the key.+ // - #v: Element type of the value.+ //+ // Notes:+ // - The key comparison takes precedence over the value comparison.+ //+ // Example:+ //+ // Bool lt <- x `KeyValueH:lessThan<?,?>` y+ @category lessThan<#k,#v>+ #k defines LessThan<#k>+ #v defines LessThan<#v>+ (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)++ // The same as lessThan, but with custom comparators.+ //+ // Params:+ // - #k: Element type of the key.+ // - #v: Element type of the value.+ // - #kk: Comparator type providing the LessThan<#k> comparison.+ // - #vv: Comparator type providing the LessThan<#v> comparison.+ //+ // Notes:+ // - The key comparison takes precedence over the value comparison.+ //+ // Example:+ //+ // // Ignore the value and compare Int keys.+ // Bool lt <- x `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` y+ @category lessThanWith<#k,#v,#kk,#vv>+ #kk defines LessThan<#k>+ #vv defines LessThan<#v>+ (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)++ // Compare for equals.+ //+ // Params:+ // - #k: Element type of the key.+ // - #v: Element type of the value.+ //+ // Example:+ //+ // Bool eq <- x `KeyValueH:equals<?,?>` y+ @category equals<#k,#v>+ #k defines Equals<#k>+ #v defines Equals<#v>+ (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)++ // The same as equals, but with custom comparators.+ //+ // Params:+ // - #k: Element type of the key.+ // - #v: Element type of the value.+ // - #kk: Comparator type providing the Equals<#k> comparison.+ // - #vv: Comparator type providing the Equals<#v> comparison.+ //+ // Example:+ //+ // // Ignore the key and compare Int values.+ // Bool eq <- x `KeyValueH:equalsWith<?,?,AlwaysEqual,Int>` y+ @category equalsWith<#k,#v,#kk,#vv>+ #kk defines Equals<#k>+ #vv defines Equals<#v>+ (KeyValue<#k,#v>,KeyValue<#k,#v>) -> (Bool)+}
+ lib/container/helpers.0rt view
@@ -0,0 +1,107 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "comparator helper tests" {+ success+}++unittest keyValueHLessThan {+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:lessThan<?,?>` KV.new(1,"a"),false)+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:lessThan<?,?>` KV.new(1,"b"),true)+ \ Testing.checkEquals<?>(KV.new(2,"a") `KeyValueH:lessThan<?,?>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(1,"b") `KeyValueH:lessThan<?,?>` KV.new(2,"a"),true)+}++unittest keyValueHLessThanWith {+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(1,"a"),false)+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(2,"a") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(1,"b") `KeyValueH:lessThanWith<?,?,Int,AlwaysEqual>` KV.new(2,"a"),true)++ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(1,"a"),false)+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(1,"b"),true)+ \ Testing.checkEquals<?>(KV.new(2,"a") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(1,"b"),true)+ \ Testing.checkEquals<?>(KV.new(1,"b") `KeyValueH:lessThanWith<?,?,AlwaysEqual,String>` KV.new(2,"a"),false)+}++unittest keyValueHEquals {+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:equals<?,?>` KV.new(1,"a"),true)+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:equals<?,?>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(2,"a") `KeyValueH:equals<?,?>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(1,"b") `KeyValueH:equals<?,?>` KV.new(2,"a"),false)+}++unittest keyValueHEqualsWith {+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(1,"a"),true)+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"),true)+ \ Testing.checkEquals<?>(KV.new(2,"a") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(1,"b") `KeyValueH:equalsWith<?,?,Int,AlwaysEqual>` KV.new(2,"a"),false)++ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(1,"a"),true)+ \ Testing.checkEquals<?>(KV.new(1,"a") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(2,"a") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(1,"b"),false)+ \ Testing.checkEquals<?>(KV.new(1,"b") `KeyValueH:equalsWith<?,?,AlwaysEqual,String>` KV.new(2,"a"),false)+}++unittest integrationTest {+ SearchTree<Int,String> tree1 <- SearchTree<Int,String>.new()+ .set(1,"d").set(2,"c").set(3,"b").set(4,"a")+ SearchTree<Int,String> tree2 <- SearchTree<Int,String>.new()+ .set(1,"a").set(2,"b").set(3,"c").set(4,"d")++ \ Testing.checkEquals<?>(tree1.defaultOrder() `OrderH:equalsWith<?,KVEquals<Int,AlwaysEqual>>` tree2.defaultOrder(),true)+ \ Testing.checkEquals<?>(tree1.defaultOrder() `OrderH:equalsWith<?,KVEquals<Int,String>>` tree2.defaultOrder(),false)+ \ Testing.checkEquals<?>(tree1.defaultOrder() `OrderH:equalsWith<?,KVEquals<AlwaysEqual,String>>` tree2.defaultOrder(),false)+}++concrete KVEquals<#k,#v> {+ defines Equals<KeyValue<Int,String>>+ #k defines Equals<Int>+ #v defines Equals<String>+}++define KVEquals {+ equals (x,y) {+ return x `KeyValueH:equalsWith<?,?,#k,#v>` y+ }+}++concrete KV {+ refines KeyValue<Int,String>++ @type new (Int,String) -> (KV)+}++define KV {+ $ReadOnly[key,value]$++ @value Int key+ @value String value++ new (k,v) {+ return KV{ k, v }+ }++ getKey () {+ return key+ }++ getValue () {+ return value+ }+}
+ lib/container/helpers.0rx view
@@ -0,0 +1,45 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define KeyValueH {+ lessThan (x,y) {+ return lessThanWith<#k,#v,#k,#v>(x,y)+ }++ lessThanWith (x,y) {+ if (x.getKey() `#kk.lessThan` y.getKey()) {+ return true+ } elif (y.getKey() `#kk.lessThan` x.getKey()) {+ return false+ } else {+ return x.getValue() `#vv.lessThan` y.getValue()+ }+ }++ equals (x,y) {+ return equalsWith<#k,#v,#k,#v>(x,y)+ }++ equalsWith (x,y) {+ if (!(x.getKey() `#kk.equals` y.getKey())) {+ return false+ } else {+ return x.getValue() `#vv.equals` y.getValue()+ }+ }+}
lib/container/interfaces.0rp view
@@ -51,6 +51,29 @@ get (#k) -> (optional #v) } +// Writing to a set of values.+//+// Params:+// - #k: The type stored in the set.+@value interface SetWriter<#k|> {+ add (#k) -> (#self)+ remove (#k) -> (#self)+}++// Checking a set of values.+//+// Params:+// - #k: The type stored in the set.+@value interface SetReader<#k|> {+ member (#k) -> (Bool)+}++// Factory for creating a new key-value pair.+@type interface KVFactory<#k,#v|> {+ // Create a new pair from the provided key and value.+ newNode (#k,#v) -> (#self)+}+ // A single key-value pair from a KVReader. @value interface KeyValue<|#k,#v> { // Get the key.
lib/container/search-tree.0rp view
@@ -22,6 +22,7 @@ // - #k: The key type. // - #v: The value type. concrete SearchTree<#k,#v> {+ refines Container refines DefaultOrder<KeyValue<#k,#v>> refines KVWriter<#k,#v> refines KVReader<#k,#v>@@ -60,23 +61,4 @@ // - If the key does not exist in the SearchTree, the position right after // where it would be (in the reverse direction) is returned. @value getReverse (#k) -> (optional Order<KeyValue<#k,#v>>)-}--// A validated binary search tree for key-value storage.-//-// Params:-// - #k: The key type.-// - #v: The value type.-//-// Notes:-// - This is the same as SearchTree, but it validates the tree structure every-// time there is a modification, which is extremely inefficient. This should-// therefore only be used in tests.-concrete ValidatedTree<#k|#v|> {- refines KVWriter<#k,#v>- refines KVReader<#k,#v>- #k defines LessThan<#k>-- // Create an empty tree.- @type new () -> (#self) }
lib/container/search-tree.0rt view
@@ -21,7 +21,7 @@ } unittest integrationTest {- [KVWriter<Int,Int>&KVReader<Int,Int>] tree <- ValidatedTree<Int,Int>.new()+ ValidatedTree<Int,Int> tree <- ValidatedTree<Int,Int>.new() Int count <- 30 $ReadOnly[count]$ @@ -29,6 +29,7 @@ traverse (Counter.zeroIndexed(count) -> Int i) { Int new <- ((i + 13) * 3547) % count \ tree.set(new,i)+ \ Testing.checkEquals<?>(tree.size(),i+1) } // Check and remove values.@@ -54,6 +55,7 @@ .writeTo(SimpleOutput.error()) } \ tree.remove(new)+ \ Testing.checkEquals<?>(tree.size(),count-i-1) } } @@ -76,7 +78,7 @@ index <- index+1 } - \ Testing.checkEquals<?>(index,20)+ \ Testing.checkEquals<?>(index,max) } unittest reverseOrder {@@ -91,7 +93,7 @@ } // Validate the traversal order.- Int index <- 20+ Int index <- max traverse (tree.reverseOrder() -> KeyValue<Int,Int> entry) { index <- index-1 \ Testing.checkEquals<?>(entry.getKey(),index)@@ -120,7 +122,7 @@ \ Testing.checkEquals<?>((entry.getValue()*hash)%max,entry.getKey()) index <- index+1 }- \ Testing.checkEquals<?>(index,20)+ \ Testing.checkEquals<?>(index,max) } }
lib/container/search-tree.0rx view
@@ -17,187 +17,149 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define SearchTree {- @value optional Node<#k,#v> root+ @value AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>> tree new () {- return #self{ empty }+ return #self{ AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>>.new() } } + size () {+ return tree.size()+ }+ set (k,v) {- root <- Node<#k,#v>.insert(root,k,v)+ \ tree.set(k,v) return self } remove (k) {- root <- Node<#k,#v>.delete(root,k)+ \ tree.remove(k) return self } get (k) {- return Node<#k,#v>.find(root,k)+ return tree.get(k) } defaultOrder () {- return ForwardTreeOrder:create<?,?>(root)+ return ForwardTreeOrder:create<?,?>(tree.getRoot()) } reverseOrder () {- return ReverseTreeOrder:create<?,?>(root)+ return ReverseTreeOrder:create<?,?>(tree.getRoot()) } getForward (k) {- return ForwardTreeOrder:seek<?,?>(k,root)+ return ForwardTreeOrder:seek<?,?>(k,tree.getRoot()) } getReverse (k) {- return ReverseTreeOrder:seek<?,?>(k,root)+ return ReverseTreeOrder:seek<?,?>(k,tree.getRoot()) } } define ValidatedTree {- @value optional Node<#k,#v> root+ @value AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>> tree new () {- return #self{ empty }+ return #self{ AutoBinaryTree<SearchTreeNode<#k,#v>,#k,#v,BinaryTreeNode<#k,#v>>.new() } } + size () {+ return tree.size()+ }+ set (k,v) {- root <- Node<#k,#v>.insert(root,k,v)- \ Node<#k,#v>.validate(root)+ \ tree.set(k,v)+ \ validate(tree.getRoot()) return self } remove (k) {- root <- Node<#k,#v>.delete(root,k)- \ Node<#k,#v>.validate(root)+ \ tree.remove(k)+ \ validate(tree.getRoot()) return self } get (k) {- return Node<#k,#v>.find(root,k)- }-}--concrete Node<#k,#v> {- #k defines LessThan<#k>-- @type insert (optional Node<#k,#v>,#k,#v) -> (optional Node<#k,#v>)- @type delete (optional Node<#k,#v>,#k) -> (optional Node<#k,#v>)- @type find (optional Node<#k,#v>,#k) -> (optional #v)- @type validate (optional Node<#k,#v>) -> ()-- @value getLower () -> (optional Node<#k,#v>)- @value getHigher () -> (optional Node<#k,#v>)- @value getKey () -> (#k)- @value getValue () -> (#v)-}--define Node {- $ReadOnly[key]$-- @value Int height- @value #k key- @value #v value- @value optional Node<#k,#v> lower- @value optional Node<#k,#v> higher-- insert (node,k,v) {- if (!present(node)) {- return #self{ 1, k, v, empty, empty }- }- Node<#k,#v> node2 <- require(node)- if (k `#k.lessThan` node2.getKey()) {- \ node2.setLower(insert(node2.getLower(),k,v))- return rebalance(node2)- } elif (node2.getKey() `#k.lessThan` k) {- \ node2.setHigher(insert(node2.getHigher(),k,v))- return rebalance(node2)- } else {- \ node2.setValue(v)- return node2- }- }-- delete (node,k) {- if (!present(node)) {- return empty- }- Node<#k,#v> node2 <- require(node)- if (k `#k.lessThan` node2.getKey()) {- \ node2.setLower(delete(node2.getLower(),k))- return rebalance(node2)- } elif (node2.getKey() `#k.lessThan` k) {- \ node2.setHigher(delete(node2.getHigher(),k))- return rebalance(node2)- } else {- return rebalance(removeNode(node2))- }- }-- find (node,k) {- if (present(node)) {- scoped {- Node<#k,#v> node2 <- require(node)- } in if (k `#k.lessThan` node2.getKey()) {- return find(node2.getLower(),k)- } elif (node2.getKey() `#k.lessThan` k) {- return find(node2.getHigher(),k)- } else {- return node2.getValue()- }- } else {- return empty- }+ return tree.get(k) } + @type validate (optional BinaryTreeNode<#k,#v>) -> () validate (node) { if (present(node)) {- \ require(node).validateOrder()- \ require(node).validateBalance()+ \ validateOrder(require(node))+ \ validateBalance(require(node)) } } - getLower () { return lower }-- getHigher () { return higher }-- getKey () { return key }-- getValue () { return value }-- @value validateOrder () -> ()- validateOrder () {- if (present(lower)) {- if (!(require(lower).getKey() `#k.lessThan` getKey())) {+ @type validateOrder (BinaryTreeNode<#k,#v>) -> ()+ validateOrder (node) {+ if (present(node.getLower())) {+ if (!(require(node.getLower()).getKey() `#k.lessThan` node.getKey())) { fail("bad lower order") }- \ require(lower).validateOrder()+ \ validateOrder(require(node.getLower())) }- if (present(higher)) {- if (!(getKey() `#k.lessThan` require(higher).getKey())) {+ if (present(node.getHigher())) {+ if (!(node.getKey() `#k.lessThan` require(node.getHigher()).getKey())) { fail("bad higher order") }- \ require(higher).validateOrder()+ \ validateOrder(require(node.getHigher())) } } - @value validateBalance () -> ()- validateBalance () {+ @type validateBalance (BinaryTreeNode<#k,#v>) -> ()+ validateBalance (node) { scoped {- Int balance <- getBalance()+ Int balance <- 0+ if (present(node.getLower())) {+ balance <- balance-require(node.getLower()).getHeight()+ }+ if (present(node.getHigher())) {+ balance <- balance+require(node.getHigher()).getHeight()+ }+ $ReadOnly[balance]$ } in if (balance > 1 || balance < -1) { fail("out of balance: " + balance.formatted()) }- if (present(lower)) {- \ require(lower).validateBalance()+ if (present(node.getLower())) {+ \ validateBalance(require(node.getLower())) }- if (present(higher)) {- \ require(higher).validateBalance()+ if (present(node.getHigher())) {+ \ validateBalance(require(node.getHigher())) } }+} - @value updateHeight () -> ()- updateHeight () {+concrete SearchTreeNode<#k,#v> {+ defines KVFactory<#k,#v>+ refines BalancedTreeNode<SearchTreeNode<#k,#v>,#k,#v>+}++define SearchTreeNode {+ $ReadOnly[key]$++ @value Int height+ @value #k key+ @value #v value+ @value optional #self lower+ @value optional #self higher++ newNode (k,v) {+ return #self{ 1, k, v, empty, empty }+ }++ getLower () { return lower }+ setLower (l) { lower <- l }+ getHigher () { return higher }+ setHigher (h) { higher <- h }+ getKey () { return key }+ getValue () { return value }+ setValue (v) { value <- v }+ getHeight () { return height }++ updateNode () { scoped { Int l <- 0 Int h <- 0@@ -212,277 +174,5 @@ } else { height <- h + 1 }- }-- @value getBalance () -> (Int)- getBalance () {- scoped {- Int l <- 0- Int h <- 0- if (present(lower)) {- l <- require(lower).getHeight()- }- if (present(higher)) {- h <- require(higher).getHeight()- }- } in return h - l- }-- @type rebalance (optional Node<#k,#v>) -> (optional Node<#k,#v>)- rebalance (node) {- if (!present(node)) {- return empty- }- Node<#k,#v> node2 <- require(node)- \ node2.updateHeight()- scoped {- Int balance <- node2.getBalance()- } in if (balance > 1) {- return pivotLower(node2)- } elif (balance < -1) {- return pivotHigher(node2)- } else {- return node2- }- }-- @type pivotHigher (Node<#k,#v>) -> (Node<#k,#v>)- pivotHigher (node) (newNode) {- if (require(node.getLower()).getBalance() > 0) {- \ node.setLower(pivotLower(require(node.getLower())))- }- newNode <- require(node.getLower())- \ node.setLower(newNode.getHigher())- \ node.updateHeight()- \ newNode.setHigher(node)- \ newNode.updateHeight()- }-- @type pivotLower (Node<#k,#v>) -> (Node<#k,#v>)- pivotLower (node) (newNode) {- if (require(node.getHigher()).getBalance() < 0) {- \ node.setHigher(pivotHigher(require(node.getHigher())))- }- newNode <- require(node.getHigher())- \ node.setHigher(newNode.getLower())- \ node.updateHeight()- \ newNode.setLower(node)- \ newNode.updateHeight()- }-- @type removeNode (Node<#k,#v>) -> (optional Node<#k,#v>)- removeNode (node) (newNode) {- if (node.getBalance() < 0) {- optional Node<#k,#v> temp, newNode <- removeHighest(node.getLower())- \ node.setLower(temp)- } else {- optional Node<#k,#v> temp, newNode <- removeLowest(node.getHigher())- \ node.setHigher(temp)- }- if (present(newNode)) {- \ swapChildren(node,require(newNode))- \ require(newNode).updateHeight()- }- }-- @type removeHighest (optional Node<#k,#v>) -> (optional Node<#k,#v>,optional Node<#k,#v>)- removeHighest (node) (newNode,removed) {- if (!present(node)) {- return empty, empty- }- Node<#k,#v> node2 <- require(node)- if (present(node2.getHigher())) {- optional Node<#k,#v> temp, removed <- removeHighest(node2.getHigher())- \ node2.setHigher(temp)- newNode <- rebalance(node2)- } else {- newNode <- node2.getLower()- \ node2.setLower(empty)- removed <- node- }- }-- @type removeLowest (optional Node<#k,#v>) -> (optional Node<#k,#v>,optional Node<#k,#v>)- removeLowest (node) (newNode,removed) {- if (!present(node)) {- return empty, empty- }- Node<#k,#v> node2 <- require(node)- if (present(node2.getLower())) {- optional Node<#k,#v> temp, removed <- removeLowest(node2.getLower())- \ node2.setLower(temp)- newNode <- rebalance(node2)- } else {- newNode <- node2.getHigher()- \ node2.setHigher(empty)- removed <- node- }- }-- @type swapChildren (Node<#k,#v>,Node<#k,#v>) -> ()- swapChildren (l,r) {- scoped {- optional Node<#k,#v> temp <- l.getLower()- \ l.setLower(r.getLower())- } in \ r.setLower(temp)- scoped {- optional Node<#k,#v> temp <- l.getHigher()- \ l.setHigher(r.getHigher())- } in \ r.setHigher(temp)- }-- @value getHeight () -> (Int)- getHeight () { return height }-- @value setValue (#v) -> ()- setValue (v) { value <- v }-- @value setLower (optional Node<#k,#v>) -> ()- setLower (l) { lower <- l }-- @value setHigher (optional Node<#k,#v>) -> ()- setHigher (h) { higher <- h }-}--concrete TreeKeyValue<|#k,#v> {- refines KeyValue<#k,#v>-- @category create<#k,#v> (#k,#v) -> (TreeKeyValue<#k,#v>)-}--define TreeKeyValue {- $ReadOnly[key,value]$-- @value #k key- @value #v value-- create (key,value) {- return TreeKeyValue<#k,#v>{ key, value }- }-- getKey () {- return key- }-- getValue () {- return value- }-}--concrete ForwardTreeOrder<|#k,#v> {- refines Order<KeyValue<#k,#v>>-- @category create<#k,#v> (optional Node<#k,#v>) -> (optional ForwardTreeOrder<#k,#v>)-- @category seek<#k,#v>- #k defines LessThan<#k>- (#k,optional Node<#k,#v>) -> (optional ForwardTreeOrder<#k,#v>)-}--define ForwardTreeOrder {- $ReadOnly[node,prev]$-- @value Node<#k,#v> node- @value optional ForwardTreeOrder<#k,#v> prev-- create (node) (current) {- optional Node<#k,#v> node2 <- node- current <- empty- while (present(node2)) {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }- node2 <- require(node2).getLower()- }- }-- seek (key,node) (current) {- optional Node<#k,#v> node2 <- node- current <- empty- while (present(node2)) {- if (require(node2).getKey() `#k.lessThan` key) {- // Skip node2 in the traversal, since it's before key.- node2 <- require(node2).getHigher()- } elif (key `#k.lessThan` require(node2).getKey()) {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }- node2 <- require(node2).getLower()- } else {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }- break- }- }- }-- next () (current) {- // Algorithm:- // 1. Pop self from the stack.- // 2. Traverse lower to the bottom starting from the higher child of self.- optional Node<#k,#v> node2 <- node.getHigher()- current <- prev- while (present(node2)) {- current <- ForwardTreeOrder<#k,#v>{ require(node2), current }- node2 <- require(node2).getLower()- }- }-- get () {- return TreeKeyValue:create<?,?>(node.getKey(),node.getValue())- }-}--concrete ReverseTreeOrder<|#k,#v> {- refines Order<KeyValue<#k,#v>>-- @category create<#k,#v> (optional Node<#k,#v>) -> (optional ReverseTreeOrder<#k,#v>)-- @category seek<#k,#v>- #k defines LessThan<#k>- (#k,optional Node<#k,#v>) -> (optional ReverseTreeOrder<#k,#v>)-}--define ReverseTreeOrder {- $ReadOnly[node,prev]$-- @value Node<#k,#v> node- @value optional ReverseTreeOrder<#k,#v> prev-- create (node) (current) {- optional Node<#k,#v> node2 <- node- current <- empty- while (present(node2)) {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }- node2 <- require(node2).getHigher()- }- }-- seek (key,node) (current) {- optional Node<#k,#v> node2 <- node- current <- empty- while (present(node2)) {- if (require(node2).getKey() `#k.lessThan` key) {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }- node2 <- require(node2).getHigher()- } elif (key `#k.lessThan` require(node2).getKey()) {- // Skip node2 in the traversal, since it's after key.- node2 <- require(node2).getLower()- } else {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }- break- }- }- }-- next () (current) {- // Algorithm:- // 1. Pop self from the stack.- // 2. Traverse higher to the bottom starting from the lower child of self.- optional Node<#k,#v> node2 <- node.getLower()- current <- prev- while (present(node2)) {- current <- ReverseTreeOrder<#k,#v>{ require(node2), current }- node2 <- require(node2).getHigher()- }- }-- get () {- return TreeKeyValue:create<?,?>(node.getKey(),node.getValue()) } }
+ lib/container/sorting.0rp view
@@ -0,0 +1,53 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Sorting of sequences of values.+concrete Sorting {+ // In-place unstable sorting of a random-access container.+ //+ // Params:+ // - #x: Element type managed by the container.+ //+ // Notes:+ // - Worst-case performance is O(n log n).+ // - Worst-case storage is O(1).+ @category sort<#x>+ #x defines LessThan<#x>+ ([ReadAt<#x>&WriteAt<#x>]) -> ()++ // In-place unstable sorting of a random-access container.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #xx: Comparator type providing the LessThan<#x> comparison.+ //+ // Notes:+ // - Worst-case performance is O(n log n).+ // - Worst-case storage is O(1).+ //+ // Example:+ //+ // // Sort myIntContainer in reverse order. (Reversed is from lib/util.)+ // \ Sorting:sortWith<?,Reversed<Int>>(myIntContainer)+ @category sortWith<#x,#xx>+ #xx defines LessThan<#x>+ ([ReadAt<#x>&WriteAt<#x>]) -> ()++ // In-place order reversal of a random-access container.+ @category reverse<#x> ([ReadAt<#x>&WriteAt<#x>]) -> ()+}
+ lib/container/sorting.0rt view
@@ -0,0 +1,154 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "Sorting tests" {+ success+}++unittest sort {+ TestSequence original <- TestSequence.create()+ TestSequence expected <- TestSequence.create()+ Int hash <- 269+ Int size <- 137+ $ReadOnly[hash,size]$++ traverse (Counter.zeroIndexed(size) -> Int i) {+ \ original.append((i*hash)%size/3)+ \ expected.append(i/3)+ }++ \ Sorting:sort<?>(original)+ \ Testing.checkEquals<?>(original,expected)+}++unittest sortWith {+ TestSequence original <- TestSequence.create()+ TestSequence expected <- TestSequence.create()+ Int hash <- 313+ Int size <- 197+ $ReadOnly[hash,size]$++ traverse (Counter.revZeroIndexed(size) -> Int i) {+ \ original.append((i*hash)%size/3)+ \ expected.append(i/3)+ }++ \ Sorting:sortWith<?,Reversed<Int>>(original)+ \ Testing.checkEquals<?>(original,expected)+}++unittest sortEmpty {+ TestSequence original <- TestSequence.create()+ TestSequence expected <- TestSequence.create()++ \ Sorting:sort<?>(original)+ \ Testing.checkEquals<?>(original,expected)+}++unittest reverseEvenSize {+ TestSequence original <- TestSequence.create()+ TestSequence expected <- TestSequence.create()+ Int size <- 100+ $ReadOnly[size]$++ traverse (Counter.zeroIndexed(size) -> Int i) {+ \ expected.append(i)+ }++ traverse (Counter.revZeroIndexed(size) -> Int i) {+ \ original.append(i)+ }++ \ Sorting:reverse<?>(original)+ \ Testing.checkEquals<?>(original,expected)+}++unittest reverseOddSize {+ TestSequence original <- TestSequence.create()+ TestSequence expected <- TestSequence.create()+ Int size <- 101+ $ReadOnly[size]$++ traverse (Counter.zeroIndexed(size) -> Int i) {+ \ expected.append(i)+ }++ traverse (Counter.revZeroIndexed(size) -> Int i) {+ \ original.append(i)+ }++ \ Sorting:reverse<?>(original)+ \ Testing.checkEquals<?>(original,expected)+}++unittest reverseEmpty {+ TestSequence original <- TestSequence.create()+ TestSequence expected <- TestSequence.create()++ \ Sorting:reverse<?>(original)+ \ Testing.checkEquals<?>(original,expected)+}++concrete TestSequence {+ refines Formatted+ refines ReadAt<Int>+ refines WriteAt<Int>+ refines Append<Int>+ defines Equals<TestSequence>++ @type create () -> (TestSequence)+}++define TestSequence {+ @value Vector<Int> seq++ create () {+ return TestSequence{ Vector:create<Int>() }+ }++ formatted () {+ [Append<String>&Build<String>] builder <- String.builder()+ \ builder.append("{")+ traverse (seq.defaultOrder() -> Formatted x) {+ \ builder.append(" ").append(x.formatted())+ }+ return builder.append(" }").build()+ }++ size () {+ return seq.size()+ }++ readAt (i) {+ return seq.readAt(i)+ }++ writeAt (i,x) {+ \ seq.writeAt(i,x)+ return self+ }++ append (x) {+ \ seq.append(x)+ return self+ }++ equals (x,y) {+ return x `ReadAtH:equals<?>` y+ }+}
+ lib/container/sorting.0rx view
@@ -0,0 +1,104 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define Sorting {+ sort (seq) {+ \ sortWith<#x,#x>(seq)+ }++ sortWith (seq) {+ \ HeapSort<#x,#xx>.inPlace(seq)+ }++ reverse (seq) {+ traverse (Counter.zeroIndexed(seq.size()/2) -> Int i) {+ Int j <- seq.size()-i-1+ #x temp <- seq.readAt(i)+ \ seq.writeAt(i,seq.readAt(j))+ \ seq.writeAt(j,temp)+ }+ }+}++// Putting the params at the top level allows helpers to be called without+// needing to pass the params every time.+concrete HeapSort<#x,#xx> {+ #xx defines LessThan<#x>++ @type inPlace ([ReadAt<#x>&WriteAt<#x>]) -> ()+}++define HeapSort {+ $ReadOnly[seq]$++ @value [ReadAt<#x>&WriteAt<#x>] seq++ inPlace (seq) {+ \ (#self{ seq }).execute()+ }++ @value execute () -> ()+ execute () {+ // Convert the container to a heap.+ traverse (Counter.revZeroIndexed(seq.size()/2) -> Int i) {+ \ sift(i,seq.size())+ }++ // Traverse the heap and populate the container in place.+ traverse (Counter.revZeroIndexed(seq.size()) -> Int i) {+ $ReadOnly[i]$+ \ swap(0,i)+ \ sift(0,i)+ }+ }++ @value sift (Int,Int) -> ()+ sift (start,size) {+ scoped {+ Int last <- start+ Int indexLargest <- last+ $Hidden[start]$+ } in while (2*last+1 < size) {+ $ReadOnly[last]$+ Int left <- 2*last+1+ Int right <- 2*last+2+ $ReadOnly[left,right]$+ if (seq.readAt(indexLargest) `#xx.lessThan` seq.readAt(left)) {+ indexLargest <- left+ }+ if (right < size && seq.readAt(indexLargest) `#xx.lessThan` seq.readAt(right)) {+ indexLargest <- right+ }+ if (indexLargest == last) {+ break+ }+ } update {+ \ swap(last,indexLargest)+ last <- indexLargest+ }+ }++ @value swap (Int,Int) -> ()+ swap (i,j) {+ if (i != j) {+ #x temp <- seq.readAt(i)+ \ seq.writeAt(i,seq.readAt(j))+ \ seq.writeAt(j,temp)+ }+ }+}
lib/container/src/Extension_Vector.cpp view
@@ -16,7 +16,6 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -#include <mutex> #include <vector> #include "category-source.hpp"@@ -104,7 +103,6 @@ ReturnTuple Call_append(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.append")- std::lock_guard<std::mutex> lock(mutex); const S<TypeValue>& Var_arg1 = (args.At(0)); values.push_back(Var_arg1); return ReturnTuple(Var_self);@@ -121,7 +119,6 @@ ReturnTuple Call_pop(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.pop")- std::lock_guard<std::mutex> lock(mutex); if (values.empty()) { BUILTIN_FAIL(Box_String(PrimString_FromLiteral("no elements left to pop"))) }@@ -132,7 +129,6 @@ ReturnTuple Call_push(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.push")- std::lock_guard<std::mutex> lock(mutex); const S<TypeValue>& Var_arg1 = (args.At(0)); values.push_back(Var_arg1); return ReturnTuple(Var_self);@@ -140,7 +136,6 @@ ReturnTuple Call_readAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.readAt")- std::lock_guard<std::mutex> lock(mutex); const PrimInt Var_arg1 = (args.At(0))->AsInt(); if (Var_arg1 < 0 || Var_arg1 >= values.size()) { FAIL() << "index " << Var_arg1 << " is out of bounds";@@ -150,13 +145,11 @@ ReturnTuple Call_size(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.size")- std::lock_guard<std::mutex> lock(mutex); return ReturnTuple(Box_Int(values.size())); } ReturnTuple Call_writeAt(const S<TypeValue>& Var_self, const ParamTuple& params, const ValueTuple& args) final { TRACE_FUNCTION("Vector.writeAt")- std::lock_guard<std::mutex> lock(mutex); const PrimInt Var_arg1 = (args.At(0))->AsInt(); const S<TypeValue>& Var_arg2 = (args.At(1)); if (Var_arg1 < 0 || Var_arg1 >= values.size()) {@@ -166,7 +159,6 @@ return ReturnTuple(Var_self); } - std::mutex mutex; VectorType values; };
+ lib/container/tree-set.0rp view
@@ -0,0 +1,59 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++concrete TreeSet<#k> {+ refines Container+ refines DefaultOrder<#k>+ refines SetReader<#k>+ refines SetWriter<#k>+ #k defines LessThan<#k>++ // Create a new set.+ @type new () -> (#self)++ // Traverse in the default order.+ //+ // Notes:+ // - This is from DefaultOrder, but is made explicit for documentation.+ // - Traversal of the entire set is amortized O(n); however, the cost of any+ // particular iteration could be up to O(log n).+ // - The overall memory cost is O(log n).+ @value defaultOrder () -> (optional Order<#k>)++ // Traverse the set in the reverse order of defaultOrder().+ //+ // Notes:+ // - Traversal of the entire set is amortized O(n); however, the cost of any+ // particular iteration could be up to O(log n).+ // - The overall memory cost is O(log n).+ @value reverseOrder () -> (optional Order<#k>)++ // Start forward traversal (same as defaultOrder()) from the specified key.+ //+ // Notes:+ // - If the key does not exist in the SearchTree, the position right after+ // where it would be (in the forward direction) is returned.+ @value getForward (#k) -> (optional Order<#k>)++ // Start reverse traversal (same as reverseOrder()) from the specified key.+ //+ // Notes:+ // - If the key does not exist in the SearchTree, the position right after+ // where it would be (in the reverse direction) is returned.+ @value getReverse (#k) -> (optional Order<#k>)+}
+ lib/container/tree-set.0rt view
@@ -0,0 +1,172 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "TreeSet tests" {+ success+}++unittest addAndRemove {+ TreeSet<Int> set <- TreeSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ \ Testing.checkEquals<?>(set.size(),i+1)+ }++ // Remove only the odd elements.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ if (i%2 == 1) {+ // Remove it twice to ensure idempotence.+ \ set.remove(i).remove(i)+ }+ \ Testing.checkEquals<?>(set.size(),max-(i+1)/2)+ }++ // Validate set membership.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ Testing.checkEquals<?>(set.member(i),i%2 == 0)+ }+}++unittest defaultOrder {+ TreeSet<Int> set <- TreeSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order.+ Int index <- 0+ traverse (set.defaultOrder() -> Int entry) {+ \ Testing.checkEquals<?>(entry,index)+ index <- index+1+ }++ \ Testing.checkEquals<?>(index,max)+}++unittest reverseOrder {+ TreeSet<Int> set <- TreeSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order.+ Int index <- max+ traverse (set.reverseOrder() -> Int entry) {+ index <- index-1+ \ Testing.checkEquals<?>(entry,index)+ }++ \ Testing.checkEquals<?>(index,0)+}++unittest getForward {+ TreeSet<Int> set <- TreeSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order from every starting point.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ Int index <- i+ traverse (set.getForward(index) -> Int entry) {+ \ Testing.checkEquals<?>(entry,index)+ index <- index+1+ }+ \ Testing.checkEquals<?>(index,max)+ }+}++unittest getForwardNotFound {+ TreeSet<Int> set <- TreeSet<Int>.new()+ \ set.add(1).add(3).add(5)++ scoped {+ optional Order<Int> start <- set.getForward(4)+ } in if (!present(start)) {+ fail("Failed")+ } else {+ \ Testing.checkEquals<?>(require(start).get(),5)+ }++ scoped {+ optional Order<Int> start <- set.getForward(6)+ } in if (present(start)) {+ fail("Failed")+ }+}++unittest getReverse {+ TreeSet<Int> set <- TreeSet<Int>.new()+ Int hash <- 13+ Int max <- 20+ $ReadOnly[hash,max]$++ // Populate the set in a pseudo-random order.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ \ set.add((i*hash)%max)+ }++ // Validate the traversal order from every starting point.+ traverse (Counter.zeroIndexed(max) -> Int i) {+ Int index <- i+ traverse (set.getReverse(index) -> Int entry) {+ \ Testing.checkEquals<?>(entry,index)+ index <- index-1+ }+ \ Testing.checkEquals<?>(index,-1)+ }+}++unittest getReverseNotFound {+ TreeSet<Int> set <- TreeSet<Int>.new()+ \ set.add(1).add(3).add(5)++ scoped {+ optional Order<Int> start <- set.getReverse(2)+ } in if (!present(start)) {+ fail("Failed")+ } else {+ \ Testing.checkEquals<?>(require(start).get(),1)+ }++ scoped {+ optional Order<Int> start <- set.getReverse(0)+ } in if (present(start)) {+ fail("Failed")+ }+}
+ lib/container/tree-set.0rx view
@@ -0,0 +1,92 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define TreeSet {+ @value SearchTree<#k,any> tree++ new () {+ return #self{ SearchTree<#k,any>.new() }+ }++ size () {+ return tree.size()+ }++ add (k) {+ \ tree.set(k,Void.void())+ return self+ }++ remove (k) {+ \ tree.remove(k)+ return self+ }++ member (k) {+ return present(tree.get(k))+ }++ defaultOrder () {+ return TreeSetOrder<#k>.wrap(tree.defaultOrder())+ }++ reverseOrder () {+ return TreeSetOrder<#k>.wrap(tree.reverseOrder())+ }++ getForward (k) {+ return TreeSetOrder<#k>.wrap(tree.getForward(k))+ }++ getReverse (k) {+ return TreeSetOrder<#k>.wrap(tree.getReverse(k))+ }+}++concrete TreeSetOrder<#k> {+ refines Order<#k>++ @type wrap (optional Order<KeyValue<#k,any>>) -> (optional TreeSetOrder<#k>)+}++define TreeSetOrder {+ @value Order<KeyValue<#k,any>> order++ wrap (order) {+ if (!present(order)) {+ return empty+ } else {+ return #self{ require(order) }+ }+ }++ next () {+ scoped {+ optional Order<KeyValue<#k,any>> order2 <- order.next()+ } in if (present(order2)) {+ order <- require(order2)+ return self+ } else {+ return empty+ }+ }++ get () {+ return order.get().getKey()+ }+}
+ lib/container/validated-tree.0rp view
@@ -0,0 +1,34 @@+/* -----------------------------------------------------------------------------+Copyright 2019-2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$ModuleOnly$++// A validated binary search tree for key-value storage.+//+// Notes:+// - This is the same as SearchTree, but it validates the tree structure every+// time there is a modification, which is extremely inefficient. This should+// therefore only be used in tests.+concrete ValidatedTree<#k|#v|> {+ refines Container+ refines KVWriter<#k,#v>+ refines KVReader<#k,#v>+ #k defines LessThan<#k>++ @type new () -> (#self)+}
lib/math/.zeolite-module view
@@ -1,7 +1,9 @@ root: "../.." path: "lib/math" private_deps: [+ "lib/container" "lib/testing"+ "lib/util" ] extra_files: [ category_source {
+ lib/math/categorical-tree.0rp view
@@ -0,0 +1,72 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// A categorical distribution represented as a tree.+//+// Params:+// #c: The type of category (i.e., object) used in the distribution.+//+// Notes:+// - CategoricalTree is intended for use in random sampling of arbitrary objects+// based on relative weights that can be dynamically set.+// - The distribution automatically updates every time a weight is changed. This+// can be used for updating Bayesian observations while simultaneously being+// able to sample values from the distribution.+// - The complexity of most operations is O(log n) with n distinct #c values.+// - The required storage space is independent of the weights; it only depends+// on the number of distinct #c values with non-zero weights.+concrete CategoricalTree<#c> {+ refines ReadAt<#c>+ #c defines LessThan<#c>++ // Create a new distribution.+ @type new () -> (#self)++ // Get the sum of all weights in the distribution.+ @value getTotal () -> (Int)++ // Set the relative weight of a category.+ //+ // Notes:+ // - The weight must not be negative.+ @value setWeight (#c,Int) -> (#self)++ // Get the relative weight of a category.+ //+ // Notes:+ // - If the category isn't in the tree, its weight is 0.+ @value getWeight (#c) -> (Int)++ // Return the category at the given offset.+ //+ // Notes:+ // - The offset must be within [0,getTotal()). A uniform selection in that+ // range will provide samples that follow the categorical distribution+ // corresponding to the relative weights of the respective #c.+ // - The return value is deterministic. If you were to iterate over+ // [0,getTotal()), you'd get an increasing sequence of all #c in the+ // CategoricalTree, each repeated the number of times indicated by its+ // respective weight.+ @value locate (Int) -> (#c)++ // Identical to locate(). (From ReadAt.)+ @value readAt (Int) -> (#c)++ // Identical to getTotal(). (From ReadAt/Container.)+ @value size () -> (Int)+}
+ lib/math/categorical-tree.0rt view
@@ -0,0 +1,164 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "CategoricalTree tests" {+ success+}++unittest simpleInsertion {+ CategoricalTree<Int> tree <- CategoricalTree<Int>.new()+ .setWeight(1,3)+ .setWeight(6,2)+ .setWeight(3,1)+ .setWeight(5,4)+ .setWeight(4,3)+ .setWeight(2,7)++ Vector<Int> expected <- Vector:create<Int>()+ .push(1).push(1).push(1)+ .push(2).push(2).push(2).push(2).push(2).push(2).push(2)+ .push(3)+ .push(4).push(4).push(4)+ .push(5).push(5).push(5).push(5)+ .push(6).push(6)++ \ Testing.checkEquals<?>(tree.getTotal(),expected.size())+ \ Testing.checkEquals<?>(tree.getWeight(1),3)+ \ Testing.checkEquals<?>(tree.getWeight(2),7)+ \ Testing.checkEquals<?>(tree.getWeight(3),1)+ \ Testing.checkEquals<?>(tree.getWeight(4),3)+ \ Testing.checkEquals<?>(tree.getWeight(5),4)+ \ Testing.checkEquals<?>(tree.getWeight(6),2)++ traverse (Counter.zeroIndexed(tree.getTotal()) -> Int pos) {+ \ Testing.checkOptional<?>(tree.locate(pos),expected.readAt(pos))+ }+}++unittest modifySizes {+ CategoricalTree<Int> tree <- CategoricalTree<Int>.new()+ .setWeight(1,3)+ .setWeight(6,2)+ .setWeight(3,1)+ .setWeight(5,4)+ .setWeight(4,3)+ .setWeight(2,7)+ .setWeight(7,3)+ // modifications start here+ .setWeight(5,1)+ .setWeight(3,0)++ Vector<Int> expected <- Vector:create<Int>()+ .push(1).push(1).push(1)+ .push(2).push(2).push(2).push(2).push(2).push(2).push(2)+ .push(4).push(4).push(4)+ .push(5)+ .push(6).push(6)+ .push(7).push(7).push(7)++ \ Testing.checkEquals<?>(tree.getTotal(),expected.size())+ \ Testing.checkEquals<?>(tree.getWeight(1),3)+ \ Testing.checkEquals<?>(tree.getWeight(2),7)+ \ Testing.checkEquals<?>(tree.getWeight(3),0)+ \ Testing.checkEquals<?>(tree.getWeight(4),3)+ \ Testing.checkEquals<?>(tree.getWeight(5),1)+ \ Testing.checkEquals<?>(tree.getWeight(6),2)+ \ Testing.checkEquals<?>(tree.getWeight(7),3)++ traverse (Counter.zeroIndexed(tree.getTotal()) -> Int pos) {+ \ Testing.checkOptional<?>(tree.locate(pos),expected.readAt(pos))+ }++ // Use ReadAt aliases for the same functionality.+ traverse (Counter.zeroIndexed(tree.size()) -> Int pos) {+ \ Testing.checkOptional<?>(tree.readAt(pos),expected.readAt(pos))+ }+}++unittest integrationTest {+ ValidatedTree<Int> tree <- ValidatedTree<Int>.new()+ SearchTree<Int,Int> expected <- SearchTree<Int,Int>.new()++ Int count <- 137+ Int maxSize <- 15+ Int hash1 <- 379+ Int hash2 <- 457+ $ReadOnly[count,maxSize,hash1,hash2]$++ // Populate the tree with arbitrary data.+ traverse (Counter.zeroIndexed(count) -> Int i) {+ \ tree.setWeight((i*hash1)%count,(i*hash2)%maxSize)+ }++ // Overwrite the tree with real data.+ traverse (Counter.zeroIndexed(count) -> Int i) {+ Int key <- (i*hash2)%count+ Int size <- (i*hash1)%maxSize+ \ tree.setWeight(key,size)+ \ expected.set(key,size)+ }++ optional Order<KeyValue<Int,Int>> node <- expected.defaultOrder()+ Int key <- 0+ Int remaining <- 0+ traverse (Counter.zeroIndexed(tree.getTotal()) -> Int pos) {+ while (remaining < 1) {+ key <- require(node).get().getKey()+ remaining <- require(node).get().getValue()+ node <- require(node).next()+ }+ $ReadOnly[key]$+ $Hidden[node]$+ \ Testing.checkEquals<?>(tree.locate(pos),key)+ remaining <- remaining-1+ }++ // NOTE: Order does not refine Formatted => can't use checkEmpty here.+ \ Testing.checkEquals<?>(present(node),false)+ \ Testing.checkEquals<?>(remaining,0)+}+++testcase "negative size crashes" {+ crash+ require "size.+negative"+}++unittest test {+ \ CategoricalTree<Int>.new().setWeight(0,-10)+}+++testcase "negative position crashes" {+ crash+ require "position.+negative"+}++unittest test {+ \ CategoricalTree<Int>.new().locate(-10)+}+++testcase "position past end crashes" {+ crash+ require "position.+total"+}++unittest test {+ \ CategoricalTree<Int>.new().setWeight(0,1).locate(1)+}
+ lib/math/categorical-tree.0rx view
@@ -0,0 +1,231 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define CategoricalTree {+ @value AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>> tree++ new () {+ return #self{ AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>>.new() }+ }++ getTotal () {+ return CategoricalTreeNode<#c>.tryTotal(tree.getRoot())+ }++ setWeight (cat,size) {+ if (size < 0) {+ fail("size must not be negative")+ } elif (size > 0) {+ \ tree.set(cat,size)+ } else {+ \ tree.remove(cat)+ }+ return self+ }++ getWeight (cat) {+ scoped {+ optional Int size <- tree.get(cat)+ } in if (present(size)) {+ return require(size)+ } else {+ return 0+ }+ }++ locate (pos) {+ if (pos < 0) {+ fail("position must not be negative")+ } elif (pos >= getTotal()) {+ fail("position must be strictly less than the total")+ } else {+ return require(CategoricalTreeNode<#c>.findPosition(pos,tree.getRoot()))+ }+ }++ readAt (pos) {+ return locate(pos)+ }++ size () {+ return getTotal()+ }+}++define ValidatedTree {+ @value AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>> tree++ new () {+ return #self{ AutoBinaryTree<CategoricalTreeNode<#c>,#c,Int,CategoricalSearch<#c>>.new() }+ }++ getTotal () {+ return CategoricalTreeNode<#c>.tryTotal(tree.getRoot())+ }++ setWeight (cat,size) {+ if (size < 0) {+ fail("size must not be negative")+ } elif (size > 0) {+ \ tree.set(cat,size)+ } else {+ \ tree.remove(cat)+ }+ \ validateTotal(tree.getRoot())+ return self+ }++ getWeight (cat) {+ scoped {+ optional Int size <- tree.get(cat)+ } in if (present(size)) {+ return require(size)+ } else {+ return 0+ }+ }++ locate (pos) {+ if (pos < 0) {+ fail("position must not be negative")+ } elif (pos >= getTotal()) {+ fail("position must be strictly less than the total")+ } else {+ return require(CategoricalTreeNode<#c>.findPosition(pos,tree.getRoot()))+ }+ }++ @type validateTotal (optional CategoricalSearch<#c>) -> ()+ validateTotal (node) {+ if (present(node)) {+ CategoricalSearch<#c> node2 <- require(node)+ \ validateTotal(node2.getLower())+ \ validateTotal(node2.getHigher())+ Int size <- node2.getValue()+ Int lower <- CategoricalTreeNode<#c>.tryTotal(node2.getLower())+ Int higher <- CategoricalTreeNode<#c>.tryTotal(node2.getHigher())+ if (node2.getTotal() != size+lower+higher) {+ fail(String.builder()+ .append("bad total: ")+ .append(size.formatted())+ .append("+")+ .append(lower.formatted())+ .append("+")+ .append(higher.formatted())+ .append(" != ")+ .append(node2.getTotal().formatted())+ .build())+ }+ }+ }+}++@value interface CategoricalSearch<|#c> {+ refines BinaryTreeNode<#c,Int>++ getTotal () -> (Int)+}++concrete CategoricalTreeNode<#c> {+ defines KVFactory<#c,Int>+ refines CategoricalSearch<#c>+ refines BalancedTreeNode<CategoricalTreeNode<#c>,#c,Int>++ @type findPosition (Int,optional CategoricalSearch<#c>) -> (optional #c)+ @type tryTotal (optional CategoricalSearch<#c>) -> (Int)++ @value getTotal () -> (Int)+}++define CategoricalTreeNode {+ $ReadOnly[key]$++ @value Int height+ @value #c key+ @value Int size+ @value Int total+ @value optional #self lower+ @value optional #self higher++ findPosition (pos,node) (cat) {+ cat <- empty+ if (present(node)) {+ scoped {+ Int pos2 <- pos+ $Hidden[pos]$+ CategoricalSearch<#c> node2 <- require(node)+ Int lower <- tryTotal(node2.getLower())+ Int size <- node2.getValue()+ $ReadOnly[node2,lower,size]$+ } in if (pos2 < node2.getTotal()) {+ if (pos2 < lower) {+ // pos2 is in the 1st (lower) of the 3 sections.+ return findPosition(pos2,node2.getLower())+ }+ pos2 <- pos2-lower+ if (pos2 < size) {+ // pos2 is in the 2nd (middle) of the 3 sections.+ return node2.getKey()+ }+ pos2 <- pos2-size+ // pos2 is in the 3rd (higher) of the 3 sections.+ return findPosition(pos2,node2.getHigher())+ }+ }+ }++ tryTotal (node) {+ if (present(node)) {+ return require(node).getTotal()+ } else {+ return 0+ }+ }++ newNode (k,v) {+ return #self{ 1, k, v, v, empty, empty }+ }++ getLower () { return lower }+ setLower (l) { lower <- l }+ getHigher () { return higher }+ setHigher (h) { higher <- h }+ getKey () { return key }+ getValue () { return size }+ setValue (v) { size <- v }+ getHeight () { return height }+ getTotal () { return total }++ updateNode () {+ scoped {+ Int l <- 0+ Int h <- 0+ if (present(lower)) {+ l <- require(lower).getHeight()+ }+ if (present(higher)) {+ h <- require(higher).getHeight()+ }+ } in if (l > h) {+ height <- l + 1+ } else {+ height <- h + 1+ }+ total <- size+tryTotal(lower)+tryTotal(higher)+ }+}
+ lib/math/math.0rt view
@@ -0,0 +1,135 @@+/* -----------------------------------------------------------------------------+Copyright 2020 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "sanity check all functions" {+ success+}++unittest cos {+ \ Testing.checkBetween<?>(Math.cos(2.0),-0.42,-0.41)+}++unittest sin {+ \ Testing.checkBetween<?>(Math.sin(2.0),0.90,0.91)+}++unittest tan {+ \ Testing.checkBetween<?>(Math.tan(2.0),-2.19,-2.18)+}++unittest acos {+ \ Testing.checkBetween<?>(Math.acos(0.5),1.04,1.05)+}++unittest asin {+ \ Testing.checkBetween<?>(Math.asin(0.5),0.52,0.53)+}++unittest atan {+ \ Testing.checkBetween<?>(Math.atan(0.5),0.46,0.47)+}++unittest cosh {+ \ Testing.checkBetween<?>(Math.cosh(2.0),3.76,3.77)+}++unittest sinh {+ \ Testing.checkBetween<?>(Math.sinh(2.0),3.62,3.63)+}++unittest tanh {+ \ Testing.checkBetween<?>(Math.tanh(2.0),0.96,0.97)+}++unittest acosh {+ \ Testing.checkBetween<?>(Math.acosh(2.0),1.31,1.32)+}++unittest asinh {+ \ Testing.checkBetween<?>(Math.asinh(2.0),1.44,1.45)+}++unittest atanh {+ \ Testing.checkBetween<?>(Math.atanh(0.5),0.54,0.55)+}++unittest exp {+ \ Testing.checkBetween<?>(Math.exp(1.0),2.71,2.72)+}++unittest log {+ \ Testing.checkBetween<?>(Math.log(9.0),2.19,2.20)+}++unittest log10 {+ \ Testing.checkBetween<?>(Math.log10(100.0),1.99,2.01)+}++unittest log2 {+ \ Testing.checkBetween<?>(Math.log2(8.0),2.99,3.01)+}++unittest pow {+ \ Testing.checkBetween<?>(Math.pow(2.0,3.0),7.99,8.01)+}++unittest sqrt {+ \ Testing.checkBetween<?>(Math.sqrt(4.0),1.99,2.01)+}++unittest ceil {+ \ Testing.checkBetween<?>(Math.ceil(2.2),2.99,3.01)+}++unittest floor {+ \ Testing.checkBetween<?>(Math.floor(2.2),1.99,2.01)+}++unittest fmod {+ \ Testing.checkBetween<?>(Math.fmod(7.0,4.0),2.99,3.01)+}++unittest trunc {+ \ Testing.checkBetween<?>(Math.trunc(2.2),1.99,2.01)+}++unittest round {+ \ Testing.checkBetween<?>(Math.round(2.7),2.99,3.01)+}++unittest fabs {+ \ Testing.checkBetween<?>(Math.fabs(-10.0),9.99,10.01)+}++unittest isinf {+ if (!Math.isinf(Math.log(0.0))) {+ fail("Failed")+ }+}++unittest isnan {+ if (!Math.isnan(Math.sqrt(-1.0))) {+ fail("Failed")+ }+}++unittest abs {+ \ Testing.checkEquals<?>(Math.abs(-10),10)+ \ Testing.checkEquals<?>(Math.abs(10),10)+ \ Testing.checkEquals<?>(Math.abs(0),0)+}
− lib/math/tests.0rt
@@ -1,135 +0,0 @@-/* ------------------------------------------------------------------------------Copyright 2020 Kevin P. Barry--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.------------------------------------------------------------------------------ */--// Author: Kevin P. Barry [ta0kira@gmail.com]--testcase "sanity check all functions" {- success-}--unittest cos {- \ Testing.checkBetween<?>(Math.cos(2.0),-0.42,-0.41)-}--unittest sin {- \ Testing.checkBetween<?>(Math.sin(2.0),0.90,0.91)-}--unittest tan {- \ Testing.checkBetween<?>(Math.tan(2.0),-2.19,-2.18)-}--unittest acos {- \ Testing.checkBetween<?>(Math.acos(0.5),1.04,1.05)-}--unittest asin {- \ Testing.checkBetween<?>(Math.asin(0.5),0.52,0.53)-}--unittest atan {- \ Testing.checkBetween<?>(Math.atan(0.5),0.46,0.47)-}--unittest cosh {- \ Testing.checkBetween<?>(Math.cosh(2.0),3.76,3.77)-}--unittest sinh {- \ Testing.checkBetween<?>(Math.sinh(2.0),3.62,3.63)-}--unittest tanh {- \ Testing.checkBetween<?>(Math.tanh(2.0),0.96,0.97)-}--unittest acosh {- \ Testing.checkBetween<?>(Math.acosh(2.0),1.31,1.32)-}--unittest asinh {- \ Testing.checkBetween<?>(Math.asinh(2.0),1.44,1.45)-}--unittest atanh {- \ Testing.checkBetween<?>(Math.atanh(0.5),0.54,0.55)-}--unittest exp {- \ Testing.checkBetween<?>(Math.exp(1.0),2.71,2.72)-}--unittest log {- \ Testing.checkBetween<?>(Math.log(9.0),2.19,2.20)-}--unittest log10 {- \ Testing.checkBetween<?>(Math.log10(100.0),1.99,2.01)-}--unittest log2 {- \ Testing.checkBetween<?>(Math.log2(8.0),2.99,3.01)-}--unittest pow {- \ Testing.checkBetween<?>(Math.pow(2.0,3.0),7.99,8.01)-}--unittest sqrt {- \ Testing.checkBetween<?>(Math.sqrt(4.0),1.99,2.01)-}--unittest ceil {- \ Testing.checkBetween<?>(Math.ceil(2.2),2.99,3.01)-}--unittest floor {- \ Testing.checkBetween<?>(Math.floor(2.2),1.99,2.01)-}--unittest fmod {- \ Testing.checkBetween<?>(Math.fmod(7.0,4.0),2.99,3.01)-}--unittest trunc {- \ Testing.checkBetween<?>(Math.trunc(2.2),1.99,2.01)-}--unittest round {- \ Testing.checkBetween<?>(Math.round(2.7),2.99,3.01)-}--unittest fabs {- \ Testing.checkBetween<?>(Math.fabs(-10.0),9.99,10.01)-}--unittest isinf {- if (!Math.isinf(Math.log(0.0))) {- fail("Failed")- }-}--unittest isnan {- if (!Math.isnan(Math.sqrt(-1.0))) {- fail("Failed")- }-}--unittest abs {- \ Testing.checkEquals<?>(Math.abs(-10),10)- \ Testing.checkEquals<?>(Math.abs(10),10)- \ Testing.checkEquals<?>(Math.abs(0),0)-}
+ lib/math/validated-tree.0rp view
@@ -0,0 +1,36 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++$ModuleOnly$++// A validated categorical tree.+//+// Notes:+// - This is the same as CategoricalTree, but it validates the tree structure+// every time there is a modification, which is extremely inefficient. This+// should therefore only be used in tests.+concrete ValidatedTree<#c> {+ #c defines LessThan<#c>++ @type new () -> (#self)++ @value getTotal () -> (Int)+ @value setWeight (#c,Int) -> (#self)+ @value getWeight (#c) -> (Int)+ @value locate (Int) -> (#c)+}
lib/thread/condition.0rp view
@@ -74,10 +74,8 @@ // // Example: //-// ConditionWait cond <- // created elsewhere-// // scoped {-// MutexLock lock <- MutexLock.lock(cond)+// MutexLock lock <- MutexLock.lock(conditionResume) // } cleanup { // \ lock.freeResource() // } in {@@ -85,7 +83,7 @@ // } // // // signal threads to continue-// \ cond.resumeAll()+// \ conditionResume.resumeAll() @value interface ConditionResume { refines Mutex
lib/thread/thread.0rp view
@@ -28,13 +28,15 @@ // Blocks the current thread until the Thread exits. // // Notes:- // - Check isRunning() before calling. There might be a crash otherwise.+ // - There might be a crash if join() or detach() were already called, or if+ // the thread was never started in the first place. join () -> (#self) // Disassociates the running thread from this handle. // // Notes:- // - Check isRunning() before calling. There might be a crash otherwise.+ // - There might be a crash if join() or detach() were already called, or if+ // the thread was never started in the first place. detach () -> (#self) }
lib/util/counters.0rp view
@@ -20,8 +20,10 @@ concrete Counter { // Create a sequence of indices for a Container of the given size. @type zeroIndexed (Int) -> (optional Order<Int>)+ // Create a reversed sequence of indices for a Container of the given size.+ @type revZeroIndexed (Int) -> (optional Order<Int>) // Create an unbounded Int sequence.- @type unlimited () -> (optional Order<Int>)+ @type unlimited () -> (optional Order<Int>) } // Creates an Order<#x> that repeats a single value, for use with traverse.@@ -30,4 +32,22 @@ @category times<#y> (#y,Int) -> (optional Order<#y>) // Repeat the value an unlimited number of times. @category unlimited<#y> (#y) -> (optional Order<#y>)+}++// Determines min and max of two values.+concrete Ranges {+ // Get the lower value. (Defaults to the first value.)+ @category min<#x>+ #x defines LessThan<#x>+ (#x,#x) -> (#x)++ // Get the higher value. (Defaults to the second value.)+ @category max<#x>+ #x defines LessThan<#x>+ (#x,#x) -> (#x)++ // Determine the lower and higher values. (Defaults to the same order.)+ @category minMax<#x>+ #x defines LessThan<#x>+ (#x,#x) -> (#x,#x) }
lib/util/counters.0rt view
@@ -31,6 +31,17 @@ \ Testing.checkEquals<?>(index,10) } +unittest revZeroIndexed {+ Int index <- 10++ traverse (Counter.revZeroIndexed(10) -> Int i) {+ index <- index-1+ \ Testing.checkEquals<?>(i,index)+ }++ \ Testing.checkEquals<?>(index,0)+}+ unittest unlimitedCount { Int index <- 0 @@ -66,4 +77,40 @@ } \ Testing.checkEquals<?>(index,10)+}++unittest minMax {+ scoped {+ Int x, Int y <- Ranges:minMax<?>(10,3)+ } in {+ \ Testing.checkEquals<?>(x,3)+ \ Testing.checkEquals<?>(y,10)+ }++ scoped {+ Int x, Int y <- Ranges:minMax<?>(3,10)+ } in {+ \ Testing.checkEquals<?>(x,3)+ \ Testing.checkEquals<?>(y,10)+ }+}++unittest min {+ scoped {+ Int x <- Ranges:min<?>(10,3)+ } in \ Testing.checkEquals<?>(x,3)++ scoped {+ Int x <- Ranges:min<?>(3,10)+ } in \ Testing.checkEquals<?>(x,3)+}++unittest max {+ scoped {+ Int x <- Ranges:max<?>(10,3)+ } in \ Testing.checkEquals<?>(x,10)++ scoped {+ Int x <- Ranges:max<?>(3,10)+ } in \ Testing.checkEquals<?>(x,10) }
lib/util/counters.0rx view
@@ -17,28 +17,39 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] define Counter {- $ReadOnly[max]$+ $ReadOnly[limit,incr]$ refines Order<Int> @value Int current- @value Int max+ @value optional Int limit+ @value Int incr zeroIndexed (max) { if (max <= 0) { return empty } else {- return Counter{ 0, max }+ return Counter{ 0, max, 1 } } } + revZeroIndexed (max) {+ if (max <= 0) {+ return empty+ } else {+ return Counter{ max-1, -1, -1 }+ }+ }+ unlimited () {- return Counter{ 0, -1 }+ return Counter{ 0, empty, 1 } } next () {- if (max < 0 || current+1 < max) {- current <- current+1+ if (!present(limit) ||+ (incr < 0 && current+incr > require(limit)) ||+ (incr > 0 && current+incr < require(limit))) {+ current <- current+incr return self } else { return empty@@ -51,13 +62,13 @@ } define Repeat {- $ReadOnly[max,value]$+ $ReadOnly[limit,value]$ refines Order<#x> @value #x value @value Int current- @value Int max+ @value optional Int limit times (value,max) { if (max <= 0) {@@ -68,11 +79,11 @@ } unlimited (value) {- return Repeat<#y>{ value, 0, -1 }+ return Repeat<#y>{ value, 0, empty } } next () {- if (max < 0 || current+1 < max) {+ if (!present(limit) || current+1 < require(limit)) { current <- current+1 return self } else {@@ -82,5 +93,24 @@ get () { return value+ }+}++define Ranges {+ min (x,y) (z) {+ z, _ <- minMax<?>(x,y)+ }++ max (x,y) (z) {+ _, z <- minMax<?>(x,y)+ }++ minMax (x,y) {+ // NOTE: Using y < x makes the default x, y when they are equal.+ if (y `#x.lessThan` x) {+ return y, x+ } else {+ return x, y+ } } }
+ lib/util/helpers.0rp view
@@ -0,0 +1,141 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++// Helpers to extend functionality to the Order<#x> built-in.+concrete OrderH {+ // Extend lessThan, based on position-wise comparisons.+ //+ // Notes:+ // - If one sequence is a strict prefix of the other, that sequence will+ // evaluate as less-than the other.+ //+ // Example:+ //+ // Bool lt <- x.defaultOrder() `OrderH:lessThan<?>` y.defaultOrder()+ @category lessThan<#x>+ #x defines LessThan<#x>+ (optional Order<#x>,optional Order<#x>) -> (Bool)++ // The same as lessThan, but with a custom comparator.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #xx: Comparator type providing the LessThan<#x> comparison.+ //+ // Example:+ //+ // Bool lt <- x.defaultOrder() `OrderH:lessThanWith<?,Reversed<Int>>` y.defaultOrder()+ @category lessThanWith<#x,#xx>+ #xx defines LessThan<#x>+ (optional Order<#x>,optional Order<#x>) -> (Bool)++ // Extend equals, based on position-wise comparisons.+ //+ // Example:+ //+ // Bool eq <- x.defaultOrder() `OrderH:equals<?>` y.defaultOrder()+ @category equals<#x>+ #x defines Equals<#x>+ (optional Order<#x>,optional Order<#x>) -> (Bool)++ // The same as equals, but with a custom comparator.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #xx: Comparator type providing the Equals<#x> comparison.+ //+ // Example:+ //+ // Bool eq <- x.defaultOrder() `OrderH:equalsWith<?,BySize>` y.defaultOrder()+ @category equalsWith<#x,#xx>+ #xx defines Equals<#x>+ (optional Order<#x>,optional Order<#x>) -> (Bool)+}++// Helpers to extend functionality to the ReadAt<#x> built-in.+concrete ReadAtH {+ // Extend lessThan, based on position-wise comparisons.+ //+ // Notes:+ // - If one sequence is a strict prefix of the other, that sequence will+ // evaluate as less-than the other.+ //+ // Example:+ //+ // Bool lt <- x `ReadAtH:lessThan<?>` y+ @category lessThan<#x>+ #x defines LessThan<#x>+ (ReadAt<#x>,ReadAt<#x>) -> (Bool)++ // The same as lessThan, but with a custom comparator.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #xx: Comparator type providing the LessThan<#x> comparison.+ //+ // Example:+ //+ // Bool lt <- x `ReadAtH:lessThanWith<?,Reversed<Int>>` y+ @category lessThanWith<#x,#xx>+ #xx defines LessThan<#x>+ (ReadAt<#x>,ReadAt<#x>) -> (Bool)++ // Extend equals, based on position-wise comparisons.+ //+ // Example:+ //+ // Bool eq <- x `ReadAtH:equals<?>` y+ @category equals<#x>+ #x defines Equals<#x>+ (ReadAt<#x>,ReadAt<#x>) -> (Bool)++ // The same as equals, but with a custom comparator.+ //+ // Params:+ // - #x: Element type managed by the container.+ // - #xx: Comparator type providing the Equals<#x> comparison.+ //+ // Example:+ //+ // Bool eq <- x `ReadAtH:equalsWith<?,BySize>` y+ @category equalsWith<#x,#xx>+ #xx defines Equals<#x>+ (ReadAt<#x>,ReadAt<#x>) -> (Bool)+}++// Reverse an existing LessThan<#x> comparison.+concrete Reversed<#x|> {+ defines LessThan<#x>+ #x defines LessThan<#x>+}++// Base ordering on container size alone.+concrete BySize {+ defines Equals<Container>+ defines LessThan<Container>+}++// Always evaluate objects as equal.+//+// Notes:+// - This will allow comparing any two objects with each other (e.g., Int and+// ErrorOr<String>), regardless of if they are of compatible types.+concrete AlwaysEqual {+ defines Equals<any>+ defines LessThan<any>+}
+ lib/util/helpers.0rt view
@@ -0,0 +1,139 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++testcase "comparator helper tests" {+ success+}++unittest orderHLessThan {+ \ Testing.checkEquals<?>(("").defaultOrder() `OrderH:lessThan<?>` ("").defaultOrder(), false)+ \ Testing.checkEquals<?>(("a").defaultOrder() `OrderH:lessThan<?>` ("abc").defaultOrder(),true)+ \ Testing.checkEquals<?>(("b").defaultOrder() `OrderH:lessThan<?>` ("abc").defaultOrder(),false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:lessThan<?>` ("abc").defaultOrder(),false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:lessThan<?>` ("a").defaultOrder(), false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:lessThan<?>` ("b").defaultOrder(), true)+}++unittest orderHLessThanWith {+ \ Testing.checkEquals<?>(("").defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` ("").defaultOrder(), false)+ \ Testing.checkEquals<?>(("a").defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` ("abc").defaultOrder(),true)+ \ Testing.checkEquals<?>(("b").defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` ("abc").defaultOrder(),true)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` ("abc").defaultOrder(),false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` ("a").defaultOrder(), false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:lessThanWith<?,Reversed<Char>>` ("b").defaultOrder(), false)+}++unittest orderHEquals {+ \ Testing.checkEquals<?>(("").defaultOrder() `OrderH:equals<?>` ("").defaultOrder(), true)+ \ Testing.checkEquals<?>(("a").defaultOrder() `OrderH:equals<?>` ("abc").defaultOrder(),false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:equals<?>` ("abc").defaultOrder(),true)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:equals<?>` ("a").defaultOrder(), false)+}++unittest orderHEqualsWith {+ \ Testing.checkEquals<?>(("").defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` ("").defaultOrder(), true)+ \ Testing.checkEquals<?>(("a").defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` ("ABC").defaultOrder(),false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` ("ABC").defaultOrder(),true)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` ("DEF").defaultOrder(),false)+ \ Testing.checkEquals<?>(("abc").defaultOrder() `OrderH:equalsWith<?,IgnoreCase>` ("A").defaultOrder(), false)+}++unittest readAtHLessThan {+ \ Testing.checkEquals<?>("" `ReadAtH:lessThan<?>` "", false)+ \ Testing.checkEquals<?>("a" `ReadAtH:lessThan<?>` "abc",true)+ \ Testing.checkEquals<?>("b" `ReadAtH:lessThan<?>` "abc",false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:lessThan<?>` "abc",false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:lessThan<?>` "a", false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:lessThan<?>` "b", true)+}++unittest readAtHLessThanWith {+ \ Testing.checkEquals<?>("" `ReadAtH:lessThanWith<?,Reversed<Char>>` "", false)+ \ Testing.checkEquals<?>("a" `ReadAtH:lessThanWith<?,Reversed<Char>>` "abc",true)+ \ Testing.checkEquals<?>("b" `ReadAtH:lessThanWith<?,Reversed<Char>>` "abc",true)+ \ Testing.checkEquals<?>("abc" `ReadAtH:lessThanWith<?,Reversed<Char>>` "abc",false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:lessThanWith<?,Reversed<Char>>` "a", false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:lessThanWith<?,Reversed<Char>>` "b", false)+}++unittest readAtHEquals {+ \ Testing.checkEquals<?>("" `ReadAtH:equals<?>` "", true)+ \ Testing.checkEquals<?>("a" `ReadAtH:equals<?>` "abc",false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:equals<?>` "abc",true)+ \ Testing.checkEquals<?>("abc" `ReadAtH:equals<?>` "a", false)+}++unittest readAtHEqualsWith {+ \ Testing.checkEquals<?>("" `ReadAtH:equalsWith<?,IgnoreCase>` "", true)+ \ Testing.checkEquals<?>("a" `ReadAtH:equalsWith<?,IgnoreCase>` "ABC",false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:equalsWith<?,IgnoreCase>` "ABC",true)+ \ Testing.checkEquals<?>("abc" `ReadAtH:equalsWith<?,IgnoreCase>` "DEF",false)+ \ Testing.checkEquals<?>("abc" `ReadAtH:equalsWith<?,IgnoreCase>` "a", false)+}++concrete IgnoreCase {+ defines Equals<Char>+}++define IgnoreCase {+ equals (x,y) {+ return toLower(x) == toLower(y)+ }++ @type toLower (Char) -> (Char)+ toLower (c) {+ if (c >= 'A' && c <= 'Z') {+ return (c.asInt() - ('A').asInt() + ('a').asInt()).asChar()+ } else {+ return c+ }+ }+}++unittest reversed {+ \ Testing.checkEquals<?>(0 `Reversed<Int>.lessThan` 0,false)+ \ Testing.checkEquals<?>(0 `Reversed<Int>.lessThan` 1,false)+ \ Testing.checkEquals<?>(1 `Reversed<Int>.lessThan` 0,true)+}++unittest bySizeLessThan {+ \ Testing.checkEquals<?>("" `BySize.lessThan` "", false)+ \ Testing.checkEquals<?>("b" `BySize.lessThan` "ac",true)+ \ Testing.checkEquals<?>("ac" `BySize.lessThan` "b", false)+ \ Testing.checkEquals<?>("a" `BySize.lessThan` "b", false)+}++unittest bySizeEquals {+ \ Testing.checkEquals<?>("" `BySize.equals` "", true)+ \ Testing.checkEquals<?>("b" `BySize.equals` "ac",false)+ \ Testing.checkEquals<?>("ac" `BySize.equals` "b", false)+ \ Testing.checkEquals<?>("a" `BySize.equals` "b", true)+}++unittest alwaysEqualLessThan {+ \ Testing.checkEquals<?>("" `AlwaysEqual.lessThan` "", false)+ \ Testing.checkEquals<?>("b" `AlwaysEqual.lessThan` "ac",false)+ \ Testing.checkEquals<?>("ac" `AlwaysEqual.lessThan` "b", false)+}++unittest alwaysEqualEquals {+ \ Testing.checkEquals<?>("" `AlwaysEqual.equals` "", true)+ \ Testing.checkEquals<?>("b" `AlwaysEqual.equals` "ac",true)+ \ Testing.checkEquals<?>("ac" `AlwaysEqual.equals` "b", true)+ \ Testing.checkEquals<?>("a" `AlwaysEqual.equals` "b", true)+}
+ lib/util/helpers.0rx view
@@ -0,0 +1,122 @@+/* -----------------------------------------------------------------------------+Copyright 2021 Kevin P. Barry++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.+----------------------------------------------------------------------------- */++// Author: Kevin P. Barry [ta0kira@gmail.com]++define OrderH {+ lessThan (x,y) {+ return lessThanWith<#x,#x>(x,y)+ }++ lessThanWith (x,y) {+ optional Order<#x> xx <- x+ optional Order<#x> yy <- y+ $Hidden[x,y]$+ while (present(xx) && present(yy)) {+ $ReadOnly[xx,yy]$+ if (require(xx).get() `#xx.lessThan` require(yy).get()) {+ return true+ } elif (require(yy).get() `#xx.lessThan` require(xx).get()) {+ return false+ }+ } update {+ xx <- require(xx).next()+ yy <- require(yy).next()+ }+ return present(yy)+ }++ equals (x,y) {+ return equalsWith<#x,#x>(x,y)+ }++ equalsWith (x,y) {+ optional Order<#x> xx <- x+ optional Order<#x> yy <- y+ $Hidden[x,y]$+ while (present(xx) && present(yy)) {+ $ReadOnly[xx,yy]$+ if (!(require(xx).get() `#xx.equals` require(yy).get())) {+ return false+ }+ } update {+ xx <- require(xx).next()+ yy <- require(yy).next()+ }+ return !present(xx) && !present(yy)+ }+}++define ReadAtH {+ lessThan (x,y) {+ return lessThanWith<#x,#x>(x,y)+ }++ lessThanWith (x,y) {+ traverse (Counter.zeroIndexed(Ranges:min<?>(x.size(),y.size())) -> Int i) {+ $ReadOnly[i]$+ if (x.readAt(i) `#xx.lessThan` y.readAt(i)) {+ return true+ } elif (y.readAt(i) `#xx.lessThan` x.readAt(i)) {+ return false+ }+ }+ return x.size() < y.size()+ }++ equals (x,y) {+ return equalsWith<#x,#x>(x,y)+ }++ equalsWith (x,y) {+ if (x.size() != y.size()) {+ return false+ }+ traverse (Counter.zeroIndexed(x.size()) -> Int i) {+ $ReadOnly[i]$+ if (!(x.readAt(i) `#xx.equals` y.readAt(i))) {+ return false+ }+ }+ return true+ }+}++define Reversed {+ lessThan (x,y) {+ return y `#x.lessThan` x+ }+}++define BySize {+ equals (x,y) {+ return x.size() == y.size()+ }++ lessThan (x,y) {+ return x.size() < y.size()+ }+}++define AlwaysEqual {+ equals (_,_) {+ return true+ }++ lessThan (_,_) {+ return false+ }+}
lib/util/iterator.0rp view
@@ -16,17 +16,6 @@ // Author: Kevin P. Barry [ta0kira@gmail.com] -// Random-access writes. (Like the ReadAt built-in type.)-//-// Params:-// - #x: The value type to be written.-@value interface WriteAt<#x|> {- refines Container-- // Write the value at the given index and return self.- writeAt (Int,#x) -> (#self)-}- // Read at the current position. // // Params:
lib/util/mutex.0rp view
@@ -40,6 +40,17 @@ // An automatic mutex lock. // // Notes:+// - MutexLock is a bit slower than just calling lock() and unlock() directly,+// but it provides error checking, if you don't need optimal code:+// - Makes sure that lock() is called exactly once.+// - Makes sure that unlock() is called exactly once before the last reference+// to the MutexLock is released.+// - Provides a trace back to where the MutexLock was originally created, in+// addition to where you failed to call freeResource().+// - Allows you to mark the mutex as hidden (see example below) so that+// subsequent code can't mistakenly lock()/unlock() it.+// - MutexLock should never be stored as a @value member or @category member; it+// should always be scoped to a specific set of operations in a function. // - freeResource() must be called; otherwise, there will be a crash. This is to // catch code that could cause a deadlock. // - freeResource() must only be called once per MutexLock.
src/Cli/Compiler.hs view
@@ -51,7 +51,6 @@ import Parser.TextParser (SourceContext) import Types.Builtin import Types.DefinedCategory-import Types.Procedure (isLiteralCategory) import Types.TypeCategory import Types.TypeInstance @@ -109,10 +108,8 @@ let ns0 = StaticNamespace $ publicNamespace $ show compilerHash ++ path let ns1 = StaticNamespace . privateNamespace $ show time ++ show compilerHash ++ path let extensions = concat $ map getSourceCategories es- let ss = filter (not . isLiteralCategory) extensions- let ex = filter isLiteralCategory extensions cs <- loadModuleGlobals resolver p (ns0,ns1) ps Nothing deps1' deps2- let cm = createLanguageModule ex ss em cs+ let cm = createLanguageModule extensions em cs let cs2 = filter (not . hasCodeVisibility FromDependency) cs let pc = map (getCategoryName . wvData) $ filter (not . hasCodeVisibility ModuleOnly) cs2 let tc = map (getCategoryName . wvData) $ filter (hasCodeVisibility ModuleOnly) cs2@@ -267,8 +264,8 @@ [CompileMetadata] -> [CompileMetadata] -> TrackedErrorsIO () createModuleTemplates resolver p d deps1 deps2 = do (ps,xs,_) <- findSourceFiles p d- (LanguageModule _ _ _ cs0 ps0 ts0 cs1 ps1 ts1 _ _ _) <-- fmap (createLanguageModule [] [] Map.empty) $ loadModuleGlobals resolver p (PublicNamespace,PrivateNamespace) ps Nothing deps1 deps2+ (LanguageModule _ _ _ cs0 ps0 ts0 cs1 ps1 ts1 _ _) <-+ fmap (createLanguageModule [] Map.empty) $ loadModuleGlobals resolver p (PublicNamespace,PrivateNamespace) ps Nothing deps1 deps2 xs' <- zipWithContents resolver p xs ds <- mapCompilerM parseInternalSource xs' let ds2 = concat $ map (\(_,_,d2) -> d2) ds@@ -299,7 +296,7 @@ mapCompilerM_ showSkipped $ filter (not . isTestAllowed) $ cmTestFiles m ts' <- zipWithContents resolver p $ map (d </>) $ filter isTestAllowed $ cmTestFiles m path <- errorFromIO $ canonicalizePath (p </> d)- cm <- fmap (createLanguageModule [] [] em) $ loadModuleGlobals resolver path (NoNamespace,NoNamespace) [] (Just m) deps1 []+ cm <- fmap (createLanguageModule [] em) $ loadModuleGlobals resolver path (NoNamespace,NoNamespace) [] (Just m) deps1 [] mapCompilerM (runSingleTest backend cl cm path paths (m:deps2)) ts' where allowTests = Set.fromList tp isTestAllowed t = if null allowTests then True else t `Set.member` allowTests@@ -316,9 +313,9 @@ let testing = any isTestsOnly pragmas return $ PrivateSource ns testing cs' ds -createLanguageModule :: [CategoryName] -> [CategoryName] -> ExprMap c ->+createLanguageModule :: [CategoryName] -> ExprMap c -> [WithVisibility (AnyCategory c)] -> LanguageModule c-createLanguageModule ex ss em cs = lm where+createLanguageModule ss em cs = lm where lm = LanguageModule { lmPublicNamespaces = Set.fromList $ map wvData $ apply ns [with FromDependency,without ModuleOnly], lmPrivateNamespaces = Set.fromList $ map wvData $ apply ns [with FromDependency,with ModuleOnly],@@ -329,7 +326,6 @@ lmPublicLocal = map wvData $ apply cs [without FromDependency,without ModuleOnly,without TestsOnly], lmPrivateLocal = map wvData $ apply cs [without FromDependency,with ModuleOnly,without TestsOnly], lmTestingLocal = map wvData $ apply cs [without FromDependency,with TestsOnly],- lmExternal = ex, lmStreamlined = ss, lmExprMap = em }
src/Cli/RunCompiler.hs view
@@ -168,10 +168,14 @@ compileSingle d = do d' <- errorFromIO $ canonicalizePath (p </> d) (is',is2') <- maybeUseConfig d'- base <- resolveBaseModule resolver as <- fmap fixPaths $ mapCompilerM (resolveModule resolver d') is' as2 <- fmap fixPaths $ mapCompilerM (resolveModule resolver d') is2'- deps1 <- loadPublicDeps compilerHash f Map.empty (base:as)+ isBase <- isBaseModule resolver d'+ deps1 <- if isBase+ then loadPublicDeps compilerHash f Map.empty as+ else do+ base <- resolveBaseModule resolver+ loadPublicDeps compilerHash f Map.empty (base:as) deps2 <- loadPublicDeps compilerHash f (mapMetadata deps1) as2 path <- errorFromIO $ canonicalizePath p createModuleTemplates resolver path d deps1 deps2 <?? "In module \"" ++ d' ++ "\""
src/Cli/TestRunner.hs view
@@ -145,15 +145,18 @@ when (not $ any isCompilerError results) $ errorFromIO $ removeDirectoryRecursive dir return results - executeTest binary rs es res s2 (f2,c) = printOutcome $ "\nIn unittest " ++ show f2 ++ formatFullContextBrace c ??> do+ executeTest binary rs es res s2 (f2,c) = printOutcome $ context ??> do let command = TestCommand binary (takeDirectory binary) [show f2,cl]- (TestCommandResult s2' out err) <- runTestCommand b command- case (s2,s2') of- (True,False) -> collectAllM_ $ (asCompilerError res):(map compilerErrorM $ err ++ out)- (False,True) -> collectAllM_ [compilerErrorM "Expected runtime failure",- asCompilerError res <?? "\nOutput from compiler:"]- _ -> fromTrackedErrors $ checkContent rs es (lines $ show $ getCompilerWarnings res) err out+ resetBackgroundM $ do+ compilerBackgroundM $ "See output files for testcase in " ++ (takeDirectory binary)+ (TestCommandResult s2' out err) <- runTestCommand b command+ case (s2,s2') of+ (True,False) -> collectAllM_ $ (asCompilerError res):(map compilerErrorM $ err ++ out)+ (False,True) -> collectAllM_ [compilerErrorM "Expected runtime failure",+ asCompilerError res <?? "\nOutput from compiler:"]+ _ -> fromTrackedErrors $ checkContent rs es (lines $ show $ getCompilerWarnings res) err out where+ context = "\nIn unittest " ++ show f2 ++ formatFullContextBrace c printOutcome outcome = do failed <- isCompilerErrorM outcome if failed
src/Compilation/ProcedureContext.hs view
@@ -146,8 +146,11 @@ getFromAny _ = compilerErrorM $ "Use explicit type conversion to call " ++ show n ++ " from " ++ show t getFromAll ts = do+ t' <- case t of+ Just t2 -> return t2+ Nothing -> fmap (singleType . JustTypeInstance) $ ccSelfType ctx collectFirstM ts <!!- "Function " ++ show n ++ " not available for type " ++ show t ++ formatFullContextBrace c+ "Function " ++ show n ++ " not available for type " ++ show t' ++ formatFullContextBrace c getFromSingle t0 (JustParamName _ p) = do fa <- ccAllFilters ctx fs <- case p `Map.lookup` fa of
src/Compilation/ScopeContext.hs view
@@ -63,7 +63,7 @@ getProcedureScopes :: (Show c, CollectErrorsM m) => CategoryMap c -> ExprMap c -> DefinedCategory c -> m [ProcedureScope c]-getProcedureScopes ta em (DefinedCategory c n pragmas _ _ ms ps fs) = do+getProcedureScopes ta em (DefinedCategory c n pragmas _ _ ms ps fs) = message ??> do (_,t) <- getConcreteCategory ta (c,n) let params = Positional $ getCategoryParams t let typeInstance = TypeInstance n $ fmap (singleType . JustParamName False . vpParam) params@@ -92,6 +92,7 @@ let ctxV = ScopeContext ta n params vm' filters fa vv em return [ProcedureScope ctxC cp,ProcedureScope ctxT tp',ProcedureScope ctxV vp'] where+ message = "In compilation of definition for " ++ show n ++ formatFullContextBrace c checkPragma (MembersReadOnly c2 vs) = do let missing = Set.toList $ Set.fromList vs `Set.difference` allMembers mapCompilerM_ (\v -> compilerErrorM $ "Member " ++ show v ++
src/CompilerCxx/CategoryContext.hs view
@@ -34,7 +34,7 @@ import Compilation.CompilerState import Compilation.ProcedureContext import Compilation.ScopeContext-import Types.Builtin+import CompilerCxx.Code (isStoredUnboxed) import Types.DefinedCategory import Types.Procedure import Types.TypeCategory@@ -116,7 +116,7 @@ let ns0 = if isUnnamedReturns rs2 then [] else zipWith3 ReturnVariable [0..] (map ovName $ pValues $ nrNames rs2) (map pvType $ pValues rs1)- let ns = filter (isPrimitiveType . rvType) ns0+ let ns = filter (isStoredUnboxed . rvType) ns0 return $ ProcedureContext { _pcScope = s, _pcType = t,
src/CompilerCxx/Code.hs view
@@ -25,8 +25,10 @@ emptyCode, escapeChar, escapeChars,+ expressionFromLiteral, functionLabelType, indentCompiled,+ isStoredUnboxed, newFunctionLabel, noTestsOnlySourceGuard, onlyCode,@@ -66,6 +68,7 @@ import Compilation.CompilerState import CompilerCxx.Naming import Types.Builtin+import Types.Procedure (ExpressionType) import Types.TypeCategory import Types.TypeInstance @@ -115,6 +118,26 @@ showCreationTrace :: String showCreationTrace = "TRACE_CREATION"++isStoredUnboxed :: ValueType -> Bool+isStoredUnboxed t+ | t == boolRequiredValue = True+ | t == intRequiredValue = True+ | t == floatRequiredValue = True+ | t == charRequiredValue = True+ | otherwise = False++expressionFromLiteral :: PrimitiveType -> String -> (ExpressionType,ExpressionValue)+expressionFromLiteral PrimString e =+ (Positional [stringRequiredValue],UnboxedPrimitive PrimString $ "PrimString_FromLiteral(" ++ e ++ ")")+expressionFromLiteral PrimChar e =+ (Positional [charRequiredValue],UnboxedPrimitive PrimChar $ "PrimChar(" ++ e ++ ")")+expressionFromLiteral PrimInt e =+ (Positional [intRequiredValue],UnboxedPrimitive PrimInt $ "PrimInt(" ++ e ++ ")")+expressionFromLiteral PrimFloat e =+ (Positional [floatRequiredValue],UnboxedPrimitive PrimFloat $ "PrimFloat(" ++ e ++ ")")+expressionFromLiteral PrimBool e =+ (Positional [boolRequiredValue],UnboxedPrimitive PrimBool e) getFromLazy :: ExpressionValue -> ExpressionValue getFromLazy (OpaqueMulti e) = OpaqueMulti $ e ++ ".Get()"
src/CompilerCxx/CxxFiles.hs view
@@ -140,7 +140,7 @@ label f = "extern " ++ functionLabelType f ++ " " ++ functionName f ++ ";" collection | isValueConcrete t = emptyCode- | otherwise = onlyCodes ["extern const void* const " ++ collectionName name ++ ";"]+ | otherwise = onlyCodes ["extern const CollectionType " ++ collectionName name ++ ";"] getCategory2 | isInstanceInterface t = emptyCode | otherwise = declareGetCategory t@@ -242,7 +242,7 @@ (getCategoryNamespace t) (Set.fromList [getCategoryNamespace t]) req'- (addSourceIncludes $ addStreamlinedHeader t $ addIncludes req' out)+ (addTemplateIncludes $ addStreamlinedHeader t $ addIncludes req' out) filename = templateStreamlined (getCategoryName t) defined = DefinedCategory { dcContext = [],@@ -311,7 +311,7 @@ "namespace {", "const int " ++ collectionValName ++ " = 0;", "} // namespace",- "const void* const " ++ collectionName name ++ " = &" ++ collectionValName ++ ";"+ "const CollectionType " ++ collectionName name ++ " = COLLECTION_ID(&" ++ collectionValName ++ ");" ] createAllLabels = return $ onlyCodes $ concat $ map createLabels [cf,tf,vf] collectionValName = "collection_" ++ show name@@ -597,6 +597,7 @@ | testing = (testsOnlySourceGuard ++) | otherwise = (noTestsOnlySourceGuard ++) addSourceIncludes = (baseSourceIncludes ++)+ addTemplateIncludes = (templateIncludes ++) addCategoryHeader t = (["#include \"" ++ headerFilename (getCategoryName t) ++ "\""] ++) addStreamlinedHeader t = (["#include \"" ++ headerStreamlined (getCategoryName t) ++ "\""] ++) addIncludes req = (map (\i -> "#include \"" ++ headerFilename i ++ "\"") (Set.toList req) ++)@@ -696,9 +697,10 @@ " = " ++ newFunctionLabel i f ++ ";" createFunctionDispatch :: CategoryName -> SymbolScope -> [ScopedFunction c] -> CompiledData [String]-createFunctionDispatch n s fs = onlyCodes $ [typedef] ++- concat (map table $ byCategory) ++- metaTable ++ select where+createFunctionDispatch n s fs = function where+ function+ | null filtered = onlyCode $ "{ " ++ fallback ++ " }"+ | otherwise = onlyCodes $ [typedef] ++ concat (map table $ byCategory) ++ metaTable ++ select filtered = filter ((== s) . sfScope) fs flatten f = f:(concat $ map flatten $ sfMerges f) flattened = concat $ map flatten filtered@@ -722,11 +724,11 @@ [" };"] metaTable = [" static DispatchTable<CallType> all_tables[] = {"] ++ map dispatchKeyValue byCategory ++- [" DispatchTable<CallType>(),"," };"]+ [" };"] dispatchKeyValue (n2,_) = " DispatchTable<CallType>(" ++ collectionName n2 ++ ", " ++ tableName n2 ++ ")," select = [- " std::atomic_bool table_lock{0};",- " const DispatchTable<CallType>* const table = DispatchSelect(table_lock, label.collection, all_tables);",+ " static const StaticSort force_sort = all_tables;",+ " const DispatchTable<CallType>* const table = DispatchSelect(label.collection, all_tables);", " if (table) {", " if (label.function_num < 0 || label.function_num >= table->size) {", " FAIL() << \"Bad function call \" << label;",@@ -788,10 +790,9 @@ " using CallType = void(" ++ className ++ "::*)(std::vector<S<const TypeInstance>>&)const;", " static DispatchSingle<CallType> all_calls[] = {" ] ++ map dispatchKeyValue ((getCategoryName t):refines) ++ [- " DispatchSingle<CallType>(),", " };",- " std::atomic_bool table_lock{0};",- " const DispatchSingle<CallType>* const call = DispatchSelect(table_lock, &category, all_calls);",+ " static const StaticSort force_sort = all_calls;",+ " const DispatchSingle<CallType>* const call = DispatchSelect(&category, all_calls);", " if (call) {", " (this->*call->value)(args);", " return true;",
src/CompilerCxx/LanguageModule.hs view
@@ -54,7 +54,6 @@ lmPublicLocal :: [AnyCategory c], lmPrivateLocal :: [AnyCategory c], lmTestingLocal :: [AnyCategory c],- lmExternal :: [CategoryName], lmStreamlined :: [CategoryName], lmExprMap :: ExprMap c }@@ -69,7 +68,7 @@ compileLanguageModule :: (Ord c, Show c, CollectErrorsM m) => LanguageModule c -> [PrivateSource c] -> m [CxxOutput]-compileLanguageModule (LanguageModule ns0 ns1 ns2 cs0 ps0 ts0 cs1 ps1 ts1 ex ss em) xa = do+compileLanguageModule (LanguageModule ns0 ns1 ns2 cs0 ps0 ts0 cs1 ps1 ts1 ss em) xa = do let dm = mapDefByName $ concat $ map psDefine xa checkDefined dm extensions $ filter isValueConcrete (cs1 ++ ps1 ++ ts1) checkSupefluous $ Set.toList $ extensions `Set.difference` ca@@ -82,13 +81,12 @@ map (generateNativeInterface True nsPrivate) (onlyNativeInterfaces ts1) xxPrivate <- fmap concat $ mapCompilerM (compilePrivate tmPrivate tmTesting) xa xxStreamlined <- fmap concat $ mapCompilerM (streamlined tmTesting) $ nub ss- xxVerbose <- fmap concat $ mapCompilerM (verbose tmTesting) $ nub ex- let allFiles = xxInterfaces ++ xxPrivate ++ xxStreamlined ++ xxVerbose+ let allFiles = xxInterfaces ++ xxPrivate ++ xxStreamlined noDuplicateFiles $ map (\f -> (coFilename f,coNamespace f)) allFiles return allFiles where nsPublic = ns0 `Set.union` ns2 nsPrivate = ns1 `Set.union` nsPublic- extensions = Set.fromList $ ex ++ ss+ extensions = Set.fromList ss testingCats = Set.fromList $ map getCategoryName ts1 onlyNativeInterfaces = filter (not . (`Set.member` extensions) . getCategoryName) . filter (not . isValueConcrete) localCats = Set.fromList $ map getCategoryName $ cs1 ++ ps1 ++ ts1@@ -96,10 +94,6 @@ checkLocal localCats ([] :: [String]) n (_,t) <- getConcreteCategory tm ([],n) generateStreamlinedExtension (n `Set.member` testingCats) nsPrivate t- verbose tm n = do- checkLocal localCats ([] :: [String]) n- (_,t) <- getConcreteCategory tm ([],n)- generateVerboseExtension (n `Set.member` testingCats) t compilePrivate tmPrivate tmTesting (PrivateSource ns3 testing cs2 ds) = do let tm = if testing then tmTesting@@ -188,7 +182,7 @@ compileTestMain :: (Ord c, Show c, CollectErrorsM m) => LanguageModule c -> [String] -> PrivateSource c -> [TestProcedure c] -> m (CxxOutput,[(FunctionName,[c])])-compileTestMain (LanguageModule ns0 ns1 ns2 cs0 ps0 ts0 cs1 ps1 ts1 _ _ em) args ts2 tests = do+compileTestMain (LanguageModule ns0 ns1 ns2 cs0 ps0 ts0 cs1 ps1 ts1 _ em) args ts2 tests = do tm' <- tm (CompiledData req main) <- generateTestFile tm' em args tests let output = CxxOutput Nothing testFilename NoNamespace (psNamespace ts2 `Set.insert` Set.unions [ns0,ns1,ns2]) req main@@ -198,7 +192,7 @@ compileModuleMain :: (Ord c, Show c, CollectErrorsM m) => LanguageModule c -> [PrivateSource c] -> CategoryName -> FunctionName -> m CxxOutput-compileModuleMain (LanguageModule ns0 ns1 ns2 cs0 ps0 _ cs1 ps1 _ _ _ em) xa n f = do+compileModuleMain (LanguageModule ns0 ns1 ns2 cs0 ps0 _ cs1 ps1 _ _ em) xa n f = do let resolved = filter (\d -> dcName d == n) $ concat $ map psDefine $ filter (not . psTesting) xa reconcile resolved tm' <- tm
src/CompilerCxx/Naming.hs view
@@ -47,6 +47,7 @@ sourceFilename, sourceStreamlined, tableName,+ templateIncludes, templateStreamlined, testFilename, testFunctionName,@@ -94,7 +95,10 @@ baseHeaderIncludes = ["#include \"category-header.hpp\""] baseSourceIncludes :: [String]-baseSourceIncludes = ["#include \"category-source.hpp\""]+baseSourceIncludes = ["#include \"category-source.hpp\"","#include \"internal.hpp\""]++templateIncludes :: [String]+templateIncludes = ["#include \"category-source.hpp\""] mainSourceIncludes :: [String] mainSourceIncludes = ["#include \"logging.hpp\""]
src/CompilerCxx/Procedure.hs view
@@ -158,7 +158,7 @@ | isUnnamedReturns rs2 = [] | otherwise = map (\(i,(t2,n2)) -> nameReturn i (pvType t2) n2) (zip ([0..] :: [Int]) $ zip (pValues rs1) (pValues $ nrNames rs2)) nameReturn i t2 n2- | isPrimitiveType t2 = variableProxyType t2 ++ " " ++ variableName (ovName n2) ++ ";"+ | isStoredUnboxed t2 = variableProxyType t2 ++ " " ++ variableName (ovName n2) ++ ";" | otherwise = variableProxyType t2 ++ " " ++ variableName (ovName n2) ++ " = " ++ writeStoredVariable t2 (UnwrappedSingle $ "returns.At(" ++ show i ++ ")") ++ ";"@@ -537,33 +537,33 @@ compileExpression = compile where compile (Literal (StringLiteral _ l)) = do csAddRequired (Set.fromList [BuiltinString])- return (Positional [stringRequiredValue],UnboxedPrimitive PrimString $ "PrimString_FromLiteral(" ++ escapeChars l ++ ")")+ return $ expressionFromLiteral PrimString (escapeChars l) compile (Literal (CharLiteral _ l)) = do csAddRequired (Set.fromList [BuiltinChar])- return (Positional [charRequiredValue],UnboxedPrimitive PrimChar $ "PrimChar('" ++ escapeChar l ++ "')")+ return $ expressionFromLiteral PrimChar ("'" ++ escapeChar l ++ "'") compile (Literal (IntegerLiteral c True l)) = do csAddRequired (Set.fromList [BuiltinInt]) when (l > 2^(64 :: Integer) - 1) $ compilerErrorM $ "Literal " ++ show l ++ formatFullContextBrace c ++ " is greater than the max value for 64-bit unsigned" let l' = if l > 2^(63 :: Integer) - 1 then l - 2^(64 :: Integer) else l- return (Positional [intRequiredValue],UnboxedPrimitive PrimInt $ "PrimInt(" ++ show l' ++ ")")+ return $ expressionFromLiteral PrimInt (show l') compile (Literal (IntegerLiteral c False l)) = do csAddRequired (Set.fromList [BuiltinInt]) when (l > 2^(63 :: Integer) - 1) $ compilerErrorM $ "Literal " ++ show l ++ formatFullContextBrace c ++ " is greater than the max value for 64-bit signed" when ((-l) > (2^(63 :: Integer) - 2)) $ compilerErrorM $ "Literal " ++ show l ++ formatFullContextBrace c ++ " is less than the min value for 64-bit signed"- return (Positional [intRequiredValue],UnboxedPrimitive PrimInt $ "PrimInt(" ++ show l ++ ")")+ return $ expressionFromLiteral PrimInt (show l) compile (Literal (DecimalLiteral _ l e)) = do csAddRequired (Set.fromList [BuiltinFloat]) -- TODO: Check bounds.- return (Positional [floatRequiredValue],UnboxedPrimitive PrimFloat $ "PrimFloat(" ++ show l ++ "E" ++ show e ++ ")")+ return $ expressionFromLiteral PrimFloat (show l ++ "E" ++ show e) compile (Literal (BoolLiteral _ True)) = do csAddRequired (Set.fromList [BuiltinBool])- return (Positional [boolRequiredValue],UnboxedPrimitive PrimBool "true")+ return $ expressionFromLiteral PrimBool "true" compile (Literal (BoolLiteral _ False)) = do csAddRequired (Set.fromList [BuiltinBool])- return (Positional [boolRequiredValue],UnboxedPrimitive PrimBool "false")+ return $ expressionFromLiteral PrimBool "false" compile (Literal (EmptyLiteral _)) = do return (Positional [emptyType],UnwrappedSingle "Var_empty") compile (Expression _ s os) = do
src/Parser/TypeInstance.hs view
@@ -75,12 +75,13 @@ return $ box (b:e) where box n- | n == "Bool" = BuiltinBool- | n == "Char" = BuiltinChar- | n == "Int" = BuiltinInt- | n == "Float" = BuiltinFloat- | n == "String" = BuiltinString- | n == "Formatted" = BuiltinFormatted+ | n == "Bool" = BuiltinBool+ | n == "Char" = BuiltinChar+ | n == "CharBuffer" = BuiltinCharBuffer+ | n == "Int" = BuiltinInt+ | n == "Float" = BuiltinFloat+ | n == "String" = BuiltinString+ | n == "Formatted" = BuiltinFormatted | otherwise = CategoryName n instance ParseFromSource ParamName where
src/Types/Builtin.hs view
@@ -29,7 +29,6 @@ floatRequiredValue, formattedRequiredValue, intRequiredValue,- isPrimitiveType, orderOptionalValue, stringRequiredValue, ) where@@ -69,19 +68,11 @@ data PrimitiveType = PrimBool |- PrimString | PrimChar | PrimInt |- PrimFloat+ PrimFloat |+ PrimString deriving (Eq,Show)--isPrimitiveType :: ValueType -> Bool-isPrimitiveType t- | t == boolRequiredValue = True- | t == intRequiredValue = True- | t == floatRequiredValue = True- | t == charRequiredValue = True- | otherwise = False data ExpressionValue = -- Multi argument/return tuple.
src/Types/Procedure.hs view
@@ -53,7 +53,6 @@ getStatementContext, isDiscardedInput, isFunctionOperator,- isLiteralCategory, isNoTrace, isTraceCreation, isRawCodeLine,@@ -250,8 +249,11 @@ data InstanceOrInferred c = AssignedInstance [c] GeneralInstance | InferredInstance [c]- deriving (Show) +instance Show c => Show (InstanceOrInferred c) where+ show (AssignedInstance _ t) = show t+ show (InferredInstance _) = "?"+ data FunctionSpec c = FunctionSpec [c] (FunctionQualifier c) FunctionName (Positional (InstanceOrInferred c)) deriving (Show)@@ -312,14 +314,6 @@ getValueLiteralContext (DecimalLiteral c _ _) = c getValueLiteralContext (BoolLiteral c _) = c getValueLiteralContext (EmptyLiteral c) = c--isLiteralCategory :: CategoryName -> Bool-isLiteralCategory BuiltinBool = True-isLiteralCategory BuiltinChar = True-isLiteralCategory BuiltinInt = True-isLiteralCategory BuiltinFloat = True-isLiteralCategory BuiltinString = True-isLiteralCategory _ = False data ValueOperation c = ConvertedCall [c] TypeInstance (FunctionCall c) |
src/Types/TypeInstance.hs view
@@ -133,6 +133,7 @@ } | BuiltinBool | BuiltinChar |+ BuiltinCharBuffer | BuiltinInt | BuiltinFloat | BuiltinString |@@ -144,6 +145,7 @@ show (CategoryName n) = n show BuiltinBool = "Bool" show BuiltinChar = "Char"+ show BuiltinCharBuffer = "CharBuffer" show BuiltinInt = "Int" show BuiltinFloat = "Float" show BuiltinString = "String"
tests/builtin-types.0rt view
@@ -191,6 +191,41 @@ } +testcase "reduce CharBuffer" {+ success+}++unittest charBuffer {+ if (!present(reduce<CharBuffer,CharBuffer>(CharBuffer.new(0)))) {+ fail("Failed")+ }+}++unittest readAt {+ if (!present(reduce<CharBuffer,ReadAt<Char>>(CharBuffer.new(0)))) {+ fail("Failed")+ }+ if (present(reduce<CharBuffer,ReadAt<Int>>(CharBuffer.new(0)))) {+ fail("Failed")+ }+}++unittest writeAt {+ if (!present(reduce<CharBuffer,WriteAt<Char>>(CharBuffer.new(0)))) {+ fail("Failed")+ }+ if (present(reduce<CharBuffer,WriteAt<Int>>(CharBuffer.new(0)))) {+ fail("Failed")+ }+}++unittest container {+ if (!present(reduce<CharBuffer,Container>(CharBuffer.new(0)))) {+ fail("Failed")+ }+}++ testcase "reduce String" { success }@@ -235,6 +270,9 @@ if (!present(reduce<String,DefaultOrder<Char>>("a"))) { fail("Failed") }+ if (present(reduce<String,DefaultOrder<Int>>("a"))) {+ fail("Failed")+ } } unittest subSequence {@@ -243,7 +281,22 @@ } } +unittest readAt {+ if (!present(reduce<String,ReadAt<Char>>("a"))) {+ fail("Failed")+ }+ if (present(reduce<String,ReadAt<Int>>("a"))) {+ fail("Failed")+ }+} +unittest container {+ if (!present(reduce<String,Container>("a"))) {+ fail("Failed")+ }+}++ testcase "interface implementations" { success }@@ -432,6 +485,108 @@ } +testcase "CharBuffer stuff" {+ success+}++unittest writeAndRead {+ CharBuffer buffer <- CharBuffer.new(5)+ .writeAt(0,'a')+ .writeAt(1,'b')+ .writeAt(2,'c')+ .writeAt(3,'d')+ .writeAt(4,'e')+ // overwriting here+ .writeAt(1,'B')+ .writeAt(2,'C')++ \ Testing.checkEquals<?>(buffer.size(),5)+ \ Testing.checkEquals<?>(buffer.readAt(0),'a')+ \ Testing.checkEquals<?>(buffer.readAt(1),'B')+ \ Testing.checkEquals<?>(buffer.readAt(2),'C')+ \ Testing.checkEquals<?>(buffer.readAt(3),'d')+ \ Testing.checkEquals<?>(buffer.readAt(4),'e')+}++unittest resizeDown {+ CharBuffer buffer <- CharBuffer.new(5).resize(3).writeAt(2,'a')+ \ Testing.checkEquals<?>(buffer.size(),3)+ \ Testing.checkEquals<?>(buffer.readAt(2),'a')+}++unittest resizeUp {+ CharBuffer buffer <- CharBuffer.new(5).resize(7).writeAt(6,'a')+ \ Testing.checkEquals<?>(buffer.size(),7)+ \ Testing.checkEquals<?>(buffer.readAt(6),'a')+}+++testcase "CharBuffer read negative" {+ crash+ require "-10"+ require "bounds"+}++unittest test {+ \ CharBuffer.new(3).readAt(-10)+}+++testcase "CharBuffer read past end" {+ crash+ require "3"+ require "bounds"+}++unittest test {+ \ CharBuffer.new(3).readAt(3)+}+++testcase "CharBuffer write negative" {+ crash+ require "-10"+ require "bounds"+}++unittest test {+ \ CharBuffer.new(3).writeAt(-10,'a')+}+++testcase "CharBuffer write past end" {+ crash+ require "3"+ require "bounds"+}++unittest test {+ \ CharBuffer.new(3).writeAt(3,'a')+}+++testcase "CharBuffer new negative" {+ crash+ require "-10"+ require "size"+}++unittest test {+ \ CharBuffer.new(-10)+}+++testcase "CharBuffer resize negative" {+ crash+ require "-10"+ require "size"+}++unittest test {+ \ CharBuffer.new(0).resize(-10)+}++ testcase "String stuff" { success }@@ -498,7 +653,17 @@ \ Testing.checkEquals<?>(index,7) } +unittest fromCharBuffer {+ CharBuffer buffer <- CharBuffer.new(5)+ .writeAt(0,'a')+ .writeAt(1,'b')+ .writeAt(2,'c')+ .writeAt(3,'d')+ .writeAt(4,'e')+ \ Testing.checkEquals<?>(String.fromCharBuffer(buffer),"abcde")+} + testcase "String access negative" { crash require "-10"@@ -522,7 +687,7 @@ testcase "String access past end" { crash- require "100"+ require "3" require "bounds" } @@ -532,7 +697,7 @@ define Test { run () {- \ ("abc").readAt(100)+ \ ("abc").readAt(3) } } @@ -543,7 +708,7 @@ testcase "String subsequence past end" { crash- require "100"+ require "3" require "size" } @@ -553,7 +718,7 @@ define Test { run () {- \ ("abc").subSequence(1,100)+ \ ("abc").subSequence(1,3) } }
tests/function-calls.0rt view
@@ -447,3 +447,118 @@ } concrete Test {}+++testcase "large dispatch tables" {+ success+}++unittest callDispatch {+ \ Testing.checkEquals<?>(Type.new().get(),00)+ \ Testing.checkEquals<?>(Type.new().get01(),01)+ \ Testing.checkEquals<?>(Type.new().get02(),02)+ \ Testing.checkEquals<?>(Type.new().get03(),03)+ \ Testing.checkEquals<?>(Type.new().get04(),04)+ \ Testing.checkEquals<?>(Type.new().get05(),05)+ \ Testing.checkEquals<?>(Type.new().get06(),06)+ \ Testing.checkEquals<?>(Type.new().get07(),07)+ \ Testing.checkEquals<?>(Type.new().get08(),08)+ \ Testing.checkEquals<?>(Type.new().get09(),09)+ \ Testing.checkEquals<?>(Type.new().get10(),10)+ \ Testing.checkEquals<?>(Type.new().get11(),11)+ \ Testing.checkEquals<?>(Type.new().get12(),12)+ \ Testing.checkEquals<?>(Type.new().get13(),13)+ \ Testing.checkEquals<?>(Type.new().get14(),14)+ \ Testing.checkEquals<?>(Type.new().get15(),15)+ \ Testing.checkEquals<?>(Type.new().get16(),16)+ \ Testing.checkEquals<?>(Type.new().get17(),17)+ \ Testing.checkEquals<?>(Type.new().get18(),18)+}++unittest reduceBuiltin {+ \ Testing.checkPresent(reduce<Type,Type>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base01>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base02>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base03>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base04>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base05>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base06>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base07>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base08>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base09>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base10>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base11>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base12>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base13>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base14>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base15>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base16>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base17>(Type.new()))+ \ Testing.checkPresent(reduce<Type,Base18>(Type.new()))+}++concrete Type {+ refines Base01+ refines Base02+ refines Base03+ refines Base04+ refines Base05+ refines Base06+ refines Base07+ refines Base08+ refines Base09+ refines Base10+ refines Base11+ refines Base12+ refines Base13+ refines Base14+ refines Base15+ refines Base16+ refines Base17+ refines Base18++ @type new () -> (Type)+ @value get () -> (Int)+}++define Type {+ new () { return Type{ } }+ get () { return 00 }+ get01 () { return 01 }+ get02 () { return 02 }+ get03 () { return 03 }+ get04 () { return 04 }+ get05 () { return 05 }+ get06 () { return 06 }+ get07 () { return 07 }+ get08 () { return 08 }+ get09 () { return 09 }+ get10 () { return 10 }+ get11 () { return 11 }+ get12 () { return 12 }+ get13 () { return 13 }+ get14 () { return 14 }+ get15 () { return 15 }+ get16 () { return 16 }+ get17 () { return 17 }+ get18 () { return 18 }+}++@value interface Base01 { get01 () -> (Int) }+@value interface Base02 { get02 () -> (Int) }+@value interface Base03 { get03 () -> (Int) }+@value interface Base04 { get04 () -> (Int) }+@value interface Base05 { get05 () -> (Int) }+@value interface Base06 { get06 () -> (Int) }+@value interface Base07 { get07 () -> (Int) }+@value interface Base08 { get08 () -> (Int) }+@value interface Base09 { get09 () -> (Int) }+@value interface Base10 { get10 () -> (Int) }+@value interface Base11 { get11 () -> (Int) }+@value interface Base12 { get12 () -> (Int) }+@value interface Base13 { get13 () -> (Int) }+@value interface Base14 { get14 () -> (Int) }+@value interface Base15 { get15 () -> (Int) }+@value interface Base16 { get16 () -> (Int) }+@value interface Base17 { get17 () -> (Int) }+@value interface Base18 { get18 () -> (Int) }
tests/regressions.0rt view
@@ -86,6 +86,7 @@ call2 (_) {} } + testcase "Issue #73 is not re-broken by #self" { // https://github.com/ta0kira/zeolite/issues/73 success
zeolite-lang.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.2 name: zeolite-lang-version: 0.16.1.0+version: 0.17.0.0 synopsis: Zeolite is a statically-typed, general-purpose programming language. description:@@ -68,10 +68,10 @@ data-files: base/.zeolite-module, base/*.0rp,- base/*.cc,- base/*.cpp, base/*.hpp, base/*.h,+ base/src/*.cc,+ base/src/*.cpp, example/hello/README.md, example/hello/*.0rx, example/parser/.zeolite-module,@@ -99,6 +99,7 @@ lib/math/README.md, lib/math/.zeolite-module, lib/math/*.0rp,+ lib/math/*.0rx, lib/math/*.0rt, lib/math/src/*.cpp, lib/testing/README.md,