packages feed

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 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,