LLVMFuzzerTestOneInput:
   13|  5.44k|{
   14|  5.44k|  if(size < 4)
  ------------------
  |  Branch (14:6): [True: 2, False: 5.44k]
  ------------------
   15|      2|  {
   16|      2|    return 0;
   17|      2|  }
   18|       |
   19|  5.44k|  FuzzedDataProvider fuzz_data(data, size);
   20|       |
   21|  5.44k|  try
   22|  5.44k|  {
   23|  5.44k|    BT::Ast::Environment env;
   24|  5.44k|    env.vars = BT::Blackboard::create();
   25|  5.44k|    env.enums = std::make_shared<BT::EnumsTable>();
   26|       |
   27|       |    // Add some test variables to the blackboard
   28|  5.44k|    env.vars->set("test_int", 42);
   29|  5.44k|    env.vars->set("test_double", 3.14);
   30|  5.44k|    env.vars->set("test_bool", true);
   31|  5.44k|    env.vars->set("test_string", std::string("test"));
   32|       |
   33|       |    // Add some test enums
   34|  5.44k|    (*env.enums)["RUNNING"] = 0;
   35|  5.44k|    (*env.enums)["SUCCESS"] = 1;
   36|  5.44k|    (*env.enums)["FAILURE"] = 2;
   37|       |
   38|  5.44k|    std::string script = fuzz_data.ConsumeRandomLengthString();
   39|       |
   40|  5.44k|    auto validation_result = BT::ValidateScript(script);
   41|       |
   42|  5.44k|    if(!validation_result)
  ------------------
  |  Branch (42:8): [True: 1.51k, False: 3.93k]
  ------------------
   43|  1.51k|    {
   44|  1.51k|      auto parsed_script = BT::ParseScript(script);
   45|  1.51k|      if(parsed_script)
  ------------------
  |  Branch (45:10): [True: 0, False: 1.51k]
  ------------------
   46|      0|      {
   47|      0|        try
   48|      0|        {
   49|      0|          auto result = parsed_script.value()(env);
   50|       |
   51|      0|          if(result.isNumber())
  ------------------
  |  Branch (51:14): [True: 0, False: 0]
  ------------------
   52|      0|          {
   53|      0|            volatile auto num = result.cast<double>();
   54|      0|          }
   55|       |
   56|      0|          env.vars->set("result", result);
   57|       |
   58|      0|          BT::Any read_back;
   59|      0|          (void)env.vars->get("result", read_back);
   60|      0|        }
   61|      0|        catch(const BT::RuntimeError&)  // NOLINT(bugprone-empty-catch)
   62|      0|        {
   63|       |          // Intentionally empty - fuzzer expects exceptions
   64|      0|        }
   65|      0|      }
   66|  1.51k|    }
   67|       |
   68|  5.44k|    BT::ParseScriptAndExecute(env, script);
   69|  5.44k|  }
   70|  5.44k|  catch(const std::exception&)  // NOLINT(bugprone-empty-catch)
   71|  5.44k|  {
   72|       |    // Intentionally empty - fuzzer expects exceptions
   73|    208|  }
   74|       |
   75|  5.44k|  return 0;
   76|  5.44k|}

_ZN2BT23GetAnyFromStringFunctorIiEESt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEEv:
  234|  5.44k|{
  235|       |  if constexpr(std::is_constructible_v<StringView, T>)
  236|       |  {
  237|       |    return [](StringView str) { return Any(str); };
  238|       |  }
  239|       |  else if constexpr(std::is_same_v<BT::AnyTypeAllowed, T> || std::is_enum_v<T>)
  240|       |  {
  241|       |    return {};
  242|       |  }
  243|       |  else
  244|  5.44k|  {
  245|  5.44k|    return [](StringView str) { return Any(convertFromString<T>(str)); };
  246|  5.44k|  }
  247|  5.44k|}
_ZN2BT8PortInfoC2ENS_13PortDirectionESt10type_indexSt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEE:
  428|  16.3k|    : TypeInfo(type_info, conv), direction_(direction)
  429|  16.3k|  {}
_ZN2BT8TypeInfoC2ESt10type_indexSt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEE:
  386|  16.3k|    : type_info_(type_info), converter_(conv), type_str_(BT::demangle(type_info))
  387|  16.3k|  {}
_ZN2BT23GetAnyFromStringFunctorIdEESt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEEv:
  234|  5.44k|{
  235|       |  if constexpr(std::is_constructible_v<StringView, T>)
  236|       |  {
  237|       |    return [](StringView str) { return Any(str); };
  238|       |  }
  239|       |  else if constexpr(std::is_same_v<BT::AnyTypeAllowed, T> || std::is_enum_v<T>)
  240|       |  {
  241|       |    return {};
  242|       |  }
  243|       |  else
  244|  5.44k|  {
  245|  5.44k|    return [](StringView str) { return Any(convertFromString<T>(str)); };
  246|  5.44k|  }
  247|  5.44k|}
_ZN2BT23GetAnyFromStringFunctorIbEESt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEEv:
  234|  5.44k|{
  235|       |  if constexpr(std::is_constructible_v<StringView, T>)
  236|       |  {
  237|       |    return [](StringView str) { return Any(str); };
  238|       |  }
  239|       |  else if constexpr(std::is_same_v<BT::AnyTypeAllowed, T> || std::is_enum_v<T>)
  240|       |  {
  241|       |    return {};
  242|       |  }
  243|       |  else
  244|  5.44k|  {
  245|  5.44k|    return [](StringView str) { return Any(convertFromString<T>(str)); };
  246|  5.44k|  }
  247|  5.44k|}
_ZN2BT8PortInfoC2ENS_13PortDirectionE:
  424|  14.8k|    : TypeInfo(), direction_(direction)
  425|  14.8k|  {}
_ZN2BT8TypeInfoC2Ev:
  382|  14.8k|  TypeInfo() : type_info_(typeid(AnyTypeAllowed)), type_str_("AnyTypeAllowed")
  383|  14.8k|  {}
_ZNK2BT8TypeInfo9converterEv:
  410|    661|  {
  411|    661|    return converter_;
  412|    661|  }

_ZN2BT10Blackboard6createESt10shared_ptrIS0_E:
   75|  5.44k|  {
   76|  5.44k|    return std::shared_ptr<Blackboard>(new Blackboard(parent));
   77|  5.44k|  }
_ZN2BT10BlackboardC2ESt10shared_ptrIS0_E:
   41|  5.44k|  Blackboard(Blackboard::Ptr parent) : parent_bb_(parent)
   42|  5.44k|  {}
_ZN2BT10BlackboardD2Ev:
   79|  5.44k|  virtual ~Blackboard() = default;
_ZN2BT10Blackboard3setIiEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_:
  273|  5.44k|{
  274|  5.44k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.44k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.44k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.44k|  auto it = storage_.find(key);
  283|  5.44k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.44k, False: 0]
  ------------------
  284|  5.44k|  {
  285|       |    // create a new entry
  286|  5.44k|    Any new_value(value);
  287|  5.44k|    storage_lock.unlock();
  288|  5.44k|    std::shared_ptr<Blackboard::Entry> entry;
  289|       |    // if a new generic port is created with a string, it's type should be AnyTypeAllowed
  290|       |    if constexpr(std::is_same_v<std::string, T>)
  291|       |    {
  292|       |      entry = createEntryImpl(key, PortInfo(PortDirection::INOUT));
  293|       |    }
  294|       |    else
  295|  5.44k|    {
  296|  5.44k|      PortInfo new_port(PortDirection::INOUT, new_value.type(),
  297|  5.44k|                        GetAnyFromStringFunctor<T>());
  298|  5.44k|      entry = createEntryImpl(key, new_port);
  299|  5.44k|    }
  300|       |
  301|       |    // Lock entry_mutex before writing to prevent data races with
  302|       |    // concurrent readers (BUG-1/BUG-8 fix).
  303|  5.44k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.44k|    entry->value = new_value;
  305|  5.44k|    entry->sequence_id++;
  306|  5.44k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.44k|  }
  308|      0|  else
  309|      0|  {
  310|       |    // this is not the first time we set this entry, we need to check
  311|       |    // if the type is the same or not.
  312|       |    // Copy shared_ptr to prevent use-after-free if another thread
  313|       |    // calls unset() while we hold the reference (BUG-2 fix).
  314|      0|    auto entry_ptr = it->second;
  315|      0|    storage_lock.unlock();
  316|      0|    Entry& entry = *entry_ptr;
  317|       |
  318|      0|    std::scoped_lock scoped_lock(entry.entry_mutex);
  319|       |
  320|      0|    Any& previous_any = entry.value;
  321|      0|    Any new_value(value);
  322|       |
  323|       |    // special case: entry exists but it is not strongly typed... yet
  324|      0|    if(!entry.info.isStronglyTyped())
  ------------------
  |  Branch (324:8): [True: 0, False: 0]
  ------------------
  325|      0|    {
  326|       |      // Use the new type to create a new entry that is strongly typed.
  327|      0|      entry.info = TypeInfo::Create<T>();
  328|      0|      entry.sequence_id++;
  329|      0|      entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  330|      0|      previous_any = std::move(new_value);
  331|      0|      return;
  332|      0|    }
  333|       |
  334|      0|    std::type_index previous_type = entry.info.type();
  335|       |
  336|       |    // check type mismatch
  337|      0|    if(previous_type != std::type_index(typeid(T)) && previous_type != new_value.type())
  ------------------
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:55): [True: 0, False: 0]
  ------------------
  338|      0|    {
  339|      0|      bool mismatching = true;
  340|      0|      if(std::is_constructible<StringView, T>::value)
  ------------------
  |  Branch (340:10): [Folded, False: 0]
  ------------------
  341|      0|      {
  342|      0|        Any any_from_string = entry.info.parseString(value);
  343|      0|        if(any_from_string.empty() == false)
  ------------------
  |  Branch (343:12): [True: 0, False: 0]
  ------------------
  344|      0|        {
  345|      0|          mismatching = false;
  346|      0|          new_value = std::move(any_from_string);
  347|      0|        }
  348|      0|      }
  349|       |      // check if we are doing a safe cast between numbers
  350|       |      // for instance, it is safe to use int(100) to set
  351|       |      // a uint8_t port, but not int(-42) or int(300)
  352|       |      if constexpr(std::is_arithmetic_v<T>)
  353|      0|      {
  354|      0|        if(mismatching && isCastingSafe(previous_type, value))
  ------------------
  |  Branch (354:12): [True: 0, False: 0]
  |  Branch (354:27): [True: 0, False: 0]
  ------------------
  355|      0|        {
  356|      0|          mismatching = false;
  357|      0|        }
  358|      0|      }
  359|       |
  360|      0|      if(mismatching)
  ------------------
  |  Branch (360:10): [True: 0, False: 0]
  ------------------
  361|      0|      {
  362|      0|        debugMessage();
  363|       |
  364|      0|        auto msg = StrCat("Blackboard::set(", key,
  365|      0|                          "): once declared, "
  366|      0|                          "the type of a port shall not change. "
  367|      0|                          "Previously declared type [",
  368|      0|                          BT::demangle(previous_type), "], current type [",
  369|      0|                          BT::demangle(typeid(T)), "]");
  370|      0|        throw LogicError(msg);
  371|      0|      }
  372|      0|    }
  373|       |    // if doing set<BT::Any>, skip type check
  374|       |    if constexpr(std::is_same_v<Any, T>)
  375|       |    {
  376|       |      previous_any = new_value;
  377|       |    }
  378|       |    else
  379|      0|    {
  380|       |      // copy only if the type is compatible
  381|      0|      new_value.copyInto(previous_any);
  382|      0|    }
  383|      0|    entry.sequence_id++;
  384|      0|    entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  385|      0|  }
  386|  5.44k|}
_ZN2BT10Blackboard3setIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_:
  273|  5.44k|{
  274|  5.44k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.44k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.44k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.44k|  auto it = storage_.find(key);
  283|  5.44k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.44k, False: 0]
  ------------------
  284|  5.44k|  {
  285|       |    // create a new entry
  286|  5.44k|    Any new_value(value);
  287|  5.44k|    storage_lock.unlock();
  288|  5.44k|    std::shared_ptr<Blackboard::Entry> entry;
  289|       |    // if a new generic port is created with a string, it's type should be AnyTypeAllowed
  290|       |    if constexpr(std::is_same_v<std::string, T>)
  291|       |    {
  292|       |      entry = createEntryImpl(key, PortInfo(PortDirection::INOUT));
  293|       |    }
  294|       |    else
  295|  5.44k|    {
  296|  5.44k|      PortInfo new_port(PortDirection::INOUT, new_value.type(),
  297|  5.44k|                        GetAnyFromStringFunctor<T>());
  298|  5.44k|      entry = createEntryImpl(key, new_port);
  299|  5.44k|    }
  300|       |
  301|       |    // Lock entry_mutex before writing to prevent data races with
  302|       |    // concurrent readers (BUG-1/BUG-8 fix).
  303|  5.44k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.44k|    entry->value = new_value;
  305|  5.44k|    entry->sequence_id++;
  306|  5.44k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.44k|  }
  308|      0|  else
  309|      0|  {
  310|       |    // this is not the first time we set this entry, we need to check
  311|       |    // if the type is the same or not.
  312|       |    // Copy shared_ptr to prevent use-after-free if another thread
  313|       |    // calls unset() while we hold the reference (BUG-2 fix).
  314|      0|    auto entry_ptr = it->second;
  315|      0|    storage_lock.unlock();
  316|      0|    Entry& entry = *entry_ptr;
  317|       |
  318|      0|    std::scoped_lock scoped_lock(entry.entry_mutex);
  319|       |
  320|      0|    Any& previous_any = entry.value;
  321|      0|    Any new_value(value);
  322|       |
  323|       |    // special case: entry exists but it is not strongly typed... yet
  324|      0|    if(!entry.info.isStronglyTyped())
  ------------------
  |  Branch (324:8): [True: 0, False: 0]
  ------------------
  325|      0|    {
  326|       |      // Use the new type to create a new entry that is strongly typed.
  327|      0|      entry.info = TypeInfo::Create<T>();
  328|      0|      entry.sequence_id++;
  329|      0|      entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  330|      0|      previous_any = std::move(new_value);
  331|      0|      return;
  332|      0|    }
  333|       |
  334|      0|    std::type_index previous_type = entry.info.type();
  335|       |
  336|       |    // check type mismatch
  337|      0|    if(previous_type != std::type_index(typeid(T)) && previous_type != new_value.type())
  ------------------
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:55): [True: 0, False: 0]
  ------------------
  338|      0|    {
  339|      0|      bool mismatching = true;
  340|      0|      if(std::is_constructible<StringView, T>::value)
  ------------------
  |  Branch (340:10): [Folded, False: 0]
  ------------------
  341|      0|      {
  342|      0|        Any any_from_string = entry.info.parseString(value);
  343|      0|        if(any_from_string.empty() == false)
  ------------------
  |  Branch (343:12): [True: 0, False: 0]
  ------------------
  344|      0|        {
  345|      0|          mismatching = false;
  346|      0|          new_value = std::move(any_from_string);
  347|      0|        }
  348|      0|      }
  349|       |      // check if we are doing a safe cast between numbers
  350|       |      // for instance, it is safe to use int(100) to set
  351|       |      // a uint8_t port, but not int(-42) or int(300)
  352|       |      if constexpr(std::is_arithmetic_v<T>)
  353|      0|      {
  354|      0|        if(mismatching && isCastingSafe(previous_type, value))
  ------------------
  |  Branch (354:12): [True: 0, False: 0]
  |  Branch (354:27): [True: 0, False: 0]
  ------------------
  355|      0|        {
  356|      0|          mismatching = false;
  357|      0|        }
  358|      0|      }
  359|       |
  360|      0|      if(mismatching)
  ------------------
  |  Branch (360:10): [True: 0, False: 0]
  ------------------
  361|      0|      {
  362|      0|        debugMessage();
  363|       |
  364|      0|        auto msg = StrCat("Blackboard::set(", key,
  365|      0|                          "): once declared, "
  366|      0|                          "the type of a port shall not change. "
  367|      0|                          "Previously declared type [",
  368|      0|                          BT::demangle(previous_type), "], current type [",
  369|      0|                          BT::demangle(typeid(T)), "]");
  370|      0|        throw LogicError(msg);
  371|      0|      }
  372|      0|    }
  373|       |    // if doing set<BT::Any>, skip type check
  374|       |    if constexpr(std::is_same_v<Any, T>)
  375|       |    {
  376|       |      previous_any = new_value;
  377|       |    }
  378|       |    else
  379|      0|    {
  380|       |      // copy only if the type is compatible
  381|      0|      new_value.copyInto(previous_any);
  382|      0|    }
  383|      0|    entry.sequence_id++;
  384|      0|    entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  385|      0|  }
  386|  5.44k|}
_ZN2BT10Blackboard3setIbEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_:
  273|  5.44k|{
  274|  5.44k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.44k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.44k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.44k|  auto it = storage_.find(key);
  283|  5.44k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.44k, False: 0]
  ------------------
  284|  5.44k|  {
  285|       |    // create a new entry
  286|  5.44k|    Any new_value(value);
  287|  5.44k|    storage_lock.unlock();
  288|  5.44k|    std::shared_ptr<Blackboard::Entry> entry;
  289|       |    // if a new generic port is created with a string, it's type should be AnyTypeAllowed
  290|       |    if constexpr(std::is_same_v<std::string, T>)
  291|       |    {
  292|       |      entry = createEntryImpl(key, PortInfo(PortDirection::INOUT));
  293|       |    }
  294|       |    else
  295|  5.44k|    {
  296|  5.44k|      PortInfo new_port(PortDirection::INOUT, new_value.type(),
  297|  5.44k|                        GetAnyFromStringFunctor<T>());
  298|  5.44k|      entry = createEntryImpl(key, new_port);
  299|  5.44k|    }
  300|       |
  301|       |    // Lock entry_mutex before writing to prevent data races with
  302|       |    // concurrent readers (BUG-1/BUG-8 fix).
  303|  5.44k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.44k|    entry->value = new_value;
  305|  5.44k|    entry->sequence_id++;
  306|  5.44k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.44k|  }
  308|      0|  else
  309|      0|  {
  310|       |    // this is not the first time we set this entry, we need to check
  311|       |    // if the type is the same or not.
  312|       |    // Copy shared_ptr to prevent use-after-free if another thread
  313|       |    // calls unset() while we hold the reference (BUG-2 fix).
  314|      0|    auto entry_ptr = it->second;
  315|      0|    storage_lock.unlock();
  316|      0|    Entry& entry = *entry_ptr;
  317|       |
  318|      0|    std::scoped_lock scoped_lock(entry.entry_mutex);
  319|       |
  320|      0|    Any& previous_any = entry.value;
  321|      0|    Any new_value(value);
  322|       |
  323|       |    // special case: entry exists but it is not strongly typed... yet
  324|      0|    if(!entry.info.isStronglyTyped())
  ------------------
  |  Branch (324:8): [True: 0, False: 0]
  ------------------
  325|      0|    {
  326|       |      // Use the new type to create a new entry that is strongly typed.
  327|      0|      entry.info = TypeInfo::Create<T>();
  328|      0|      entry.sequence_id++;
  329|      0|      entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  330|      0|      previous_any = std::move(new_value);
  331|      0|      return;
  332|      0|    }
  333|       |
  334|      0|    std::type_index previous_type = entry.info.type();
  335|       |
  336|       |    // check type mismatch
  337|      0|    if(previous_type != std::type_index(typeid(T)) && previous_type != new_value.type())
  ------------------
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:55): [True: 0, False: 0]
  ------------------
  338|      0|    {
  339|      0|      bool mismatching = true;
  340|      0|      if(std::is_constructible<StringView, T>::value)
  ------------------
  |  Branch (340:10): [Folded, False: 0]
  ------------------
  341|      0|      {
  342|      0|        Any any_from_string = entry.info.parseString(value);
  343|      0|        if(any_from_string.empty() == false)
  ------------------
  |  Branch (343:12): [True: 0, False: 0]
  ------------------
  344|      0|        {
  345|      0|          mismatching = false;
  346|      0|          new_value = std::move(any_from_string);
  347|      0|        }
  348|      0|      }
  349|       |      // check if we are doing a safe cast between numbers
  350|       |      // for instance, it is safe to use int(100) to set
  351|       |      // a uint8_t port, but not int(-42) or int(300)
  352|       |      if constexpr(std::is_arithmetic_v<T>)
  353|      0|      {
  354|      0|        if(mismatching && isCastingSafe(previous_type, value))
  ------------------
  |  Branch (354:12): [True: 0, False: 0]
  |  Branch (354:27): [True: 0, False: 0]
  ------------------
  355|      0|        {
  356|      0|          mismatching = false;
  357|      0|        }
  358|      0|      }
  359|       |
  360|      0|      if(mismatching)
  ------------------
  |  Branch (360:10): [True: 0, False: 0]
  ------------------
  361|      0|      {
  362|      0|        debugMessage();
  363|       |
  364|      0|        auto msg = StrCat("Blackboard::set(", key,
  365|      0|                          "): once declared, "
  366|      0|                          "the type of a port shall not change. "
  367|      0|                          "Previously declared type [",
  368|      0|                          BT::demangle(previous_type), "], current type [",
  369|      0|                          BT::demangle(typeid(T)), "]");
  370|      0|        throw LogicError(msg);
  371|      0|      }
  372|      0|    }
  373|       |    // if doing set<BT::Any>, skip type check
  374|       |    if constexpr(std::is_same_v<Any, T>)
  375|       |    {
  376|       |      previous_any = new_value;
  377|       |    }
  378|       |    else
  379|      0|    {
  380|       |      // copy only if the type is compatible
  381|      0|      new_value.copyInto(previous_any);
  382|      0|    }
  383|      0|    entry.sequence_id++;
  384|      0|    entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  385|      0|  }
  386|  5.44k|}
_ZN2BT10Blackboard3setINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRKS7_RKT_:
  273|  5.44k|{
  274|  5.44k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.44k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.44k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.44k|  auto it = storage_.find(key);
  283|  5.44k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.44k, False: 0]
  ------------------
  284|  5.44k|  {
  285|       |    // create a new entry
  286|  5.44k|    Any new_value(value);
  287|  5.44k|    storage_lock.unlock();
  288|  5.44k|    std::shared_ptr<Blackboard::Entry> entry;
  289|       |    // if a new generic port is created with a string, it's type should be AnyTypeAllowed
  290|       |    if constexpr(std::is_same_v<std::string, T>)
  291|  5.44k|    {
  292|  5.44k|      entry = createEntryImpl(key, PortInfo(PortDirection::INOUT));
  293|       |    }
  294|       |    else
  295|       |    {
  296|       |      PortInfo new_port(PortDirection::INOUT, new_value.type(),
  297|       |                        GetAnyFromStringFunctor<T>());
  298|       |      entry = createEntryImpl(key, new_port);
  299|       |    }
  300|       |
  301|       |    // Lock entry_mutex before writing to prevent data races with
  302|       |    // concurrent readers (BUG-1/BUG-8 fix).
  303|  5.44k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.44k|    entry->value = new_value;
  305|  5.44k|    entry->sequence_id++;
  306|  5.44k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.44k|  }
  308|      0|  else
  309|      0|  {
  310|       |    // this is not the first time we set this entry, we need to check
  311|       |    // if the type is the same or not.
  312|       |    // Copy shared_ptr to prevent use-after-free if another thread
  313|       |    // calls unset() while we hold the reference (BUG-2 fix).
  314|      0|    auto entry_ptr = it->second;
  315|      0|    storage_lock.unlock();
  316|      0|    Entry& entry = *entry_ptr;
  317|       |
  318|      0|    std::scoped_lock scoped_lock(entry.entry_mutex);
  319|       |
  320|      0|    Any& previous_any = entry.value;
  321|      0|    Any new_value(value);
  322|       |
  323|       |    // special case: entry exists but it is not strongly typed... yet
  324|      0|    if(!entry.info.isStronglyTyped())
  ------------------
  |  Branch (324:8): [True: 0, False: 0]
  ------------------
  325|      0|    {
  326|       |      // Use the new type to create a new entry that is strongly typed.
  327|      0|      entry.info = TypeInfo::Create<T>();
  328|      0|      entry.sequence_id++;
  329|      0|      entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  330|      0|      previous_any = std::move(new_value);
  331|      0|      return;
  332|      0|    }
  333|       |
  334|      0|    std::type_index previous_type = entry.info.type();
  335|       |
  336|       |    // check type mismatch
  337|      0|    if(previous_type != std::type_index(typeid(T)) && previous_type != new_value.type())
  ------------------
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:8): [True: 0, False: 0]
  |  Branch (337:55): [True: 0, False: 0]
  ------------------
  338|      0|    {
  339|      0|      bool mismatching = true;
  340|      0|      if(std::is_constructible<StringView, T>::value)
  ------------------
  |  Branch (340:10): [True: 0, Folded]
  ------------------
  341|      0|      {
  342|      0|        Any any_from_string = entry.info.parseString(value);
  343|      0|        if(any_from_string.empty() == false)
  ------------------
  |  Branch (343:12): [True: 0, False: 0]
  ------------------
  344|      0|        {
  345|      0|          mismatching = false;
  346|      0|          new_value = std::move(any_from_string);
  347|      0|        }
  348|      0|      }
  349|       |      // check if we are doing a safe cast between numbers
  350|       |      // for instance, it is safe to use int(100) to set
  351|       |      // a uint8_t port, but not int(-42) or int(300)
  352|       |      if constexpr(std::is_arithmetic_v<T>)
  353|       |      {
  354|       |        if(mismatching && isCastingSafe(previous_type, value))
  355|       |        {
  356|       |          mismatching = false;
  357|       |        }
  358|       |      }
  359|       |
  360|      0|      if(mismatching)
  ------------------
  |  Branch (360:10): [True: 0, False: 0]
  ------------------
  361|      0|      {
  362|      0|        debugMessage();
  363|       |
  364|      0|        auto msg = StrCat("Blackboard::set(", key,
  365|      0|                          "): once declared, "
  366|      0|                          "the type of a port shall not change. "
  367|      0|                          "Previously declared type [",
  368|      0|                          BT::demangle(previous_type), "], current type [",
  369|      0|                          BT::demangle(typeid(T)), "]");
  370|      0|        throw LogicError(msg);
  371|      0|      }
  372|      0|    }
  373|       |    // if doing set<BT::Any>, skip type check
  374|       |    if constexpr(std::is_same_v<Any, T>)
  375|       |    {
  376|       |      previous_any = new_value;
  377|       |    }
  378|       |    else
  379|      0|    {
  380|       |      // copy only if the type is compatible
  381|      0|      new_value.copyInto(previous_any);
  382|      0|    }
  383|      0|    entry.sequence_id++;
  384|      0|    entry.stamp = std::chrono::steady_clock::now().time_since_epoch();
  385|      0|  }
  386|  5.44k|}
_ZN2BT10Blackboard5EntryC2ERKNS_8TypeInfoE:
   61|  31.2k|    Entry(const TypeInfo& _info) : info(_info)
   62|  31.2k|    {}
_ZN2BT10Blackboard5EntryD2Ev:
   64|  31.2k|    ~Entry() = default;

_ZNK4linb3any4typeEv:
  176|  4.51M|    {
  177|  4.51M|        return empty()? typeid(void) : this->vtable->type();
  ------------------
  |  Branch (177:16): [True: 4, False: 4.51M]
  ------------------
  178|  4.51M|    }
_ZNK4linb3any5emptyEv:
  169|  16.9M|    {
  170|  16.9M|        return this->vtable == nullptr;
  171|  16.9M|    }
_ZN4linb3anyC2Ev:
   72|  93.8k|        vtable(nullptr)
   73|  93.8k|    {
   74|  93.8k|    }
_ZN4linb3anyD2Ev:
  100|  6.64M|    {
  101|  6.64M|        this->clear();
  102|  6.64M|    }
_ZN4linb3any5clearEv:
  159|  6.64M|    {
  160|  6.64M|        if(!empty())
  ------------------
  |  Branch (160:12): [True: 4.53M, False: 2.11M]
  ------------------
  161|  4.53M|        {
  162|  4.53M|            this->vtable->destroy(storage);
  163|  4.53M|            this->vtable = nullptr;
  164|  4.53M|        }
  165|  6.64M|    }
_ZN4linb8any_castIdEET_RKNS_3anyE:
  468|  14.6k|{
  469|  14.6k|    auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
  470|  14.6k|#ifndef ANY_IMPL_NO_EXCEPTIONS
  471|  14.6k|    if(p == nullptr) throw bad_any_cast();
  ------------------
  |  Branch (471:8): [True: 0, False: 14.6k]
  ------------------
  472|  14.6k|#endif
  473|  14.6k|    return *p;
  474|  14.6k|}
_ZN4linb8any_castIKdEEPKT_PKNS_3anyE:
  510|  14.6k|{
  511|  14.6k|    using T = typename std::decay<ValueType>::type;
  512|       |
  513|  14.6k|#ifndef ANY_IMPL_NO_RTTI
  514|  14.6k|    if (operand && operand->is_typed(typeid(T)))
  ------------------
  |  Branch (514:9): [True: 14.6k, False: 0]
  |  Branch (514:20): [True: 14.6k, False: 0]
  ------------------
  515|       |#else
  516|       |    if (operand && operand->vtable == any::vtable_for_type<T>())
  517|       |#endif
  518|  14.6k|        return operand->cast<ValueType>();
  519|      0|    else
  520|      0|        return nullptr;
  521|  14.6k|}
_ZNK4linb3any8is_typedERKSt9type_info:
  355|   743k|    {
  356|   743k|        return is_same(this->type(), t);
  357|   743k|    }
_ZN4linb3any7is_sameERKSt9type_infoS3_:
  368|   743k|    {
  369|       |#ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
  370|       |        return &a == &b;
  371|       |#else
  372|   743k|        return a == b;
  373|   743k|#endif
  374|   743k|    }
_ZNK4linb3any4castIKdEEPKT_v:
  380|  14.6k|    {
  381|  14.6k|        return requires_allocation<typename std::decay<T>::type>::value?
  ------------------
  |  Branch (381:16): [Folded, False: 14.6k]
  ------------------
  382|      0|            reinterpret_cast<const T*>(storage.dynamic) :
  383|  14.6k|            reinterpret_cast<const T*>(&storage.stack);
  384|  14.6k|    }
_ZN4linb8any_castIN7SafeAny12SimpleStringEEET_RKNS_3anyE:
  468|   457k|{
  469|   457k|    auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
  470|   457k|#ifndef ANY_IMPL_NO_EXCEPTIONS
  471|   457k|    if(p == nullptr) throw bad_any_cast();
  ------------------
  |  Branch (471:8): [True: 0, False: 457k]
  ------------------
  472|   457k|#endif
  473|   457k|    return *p;
  474|   457k|}
_ZN4linb8any_castIKN7SafeAny12SimpleStringEEEPKT_PKNS_3anyE:
  510|   457k|{
  511|   457k|    using T = typename std::decay<ValueType>::type;
  512|       |
  513|   457k|#ifndef ANY_IMPL_NO_RTTI
  514|   457k|    if (operand && operand->is_typed(typeid(T)))
  ------------------
  |  Branch (514:9): [True: 457k, False: 0]
  |  Branch (514:20): [True: 457k, False: 0]
  ------------------
  515|       |#else
  516|       |    if (operand && operand->vtable == any::vtable_for_type<T>())
  517|       |#endif
  518|   457k|        return operand->cast<ValueType>();
  519|      0|    else
  520|      0|        return nullptr;
  521|   457k|}
_ZNK4linb3any4castIKN7SafeAny12SimpleStringEEEPKT_v:
  380|   457k|    {
  381|   457k|        return requires_allocation<typename std::decay<T>::type>::value?
  ------------------
  |  Branch (381:16): [Folded, False: 457k]
  ------------------
  382|      0|            reinterpret_cast<const T*>(storage.dynamic) :
  383|   457k|            reinterpret_cast<const T*>(&storage.stack);
  384|   457k|    }
_ZN4linb8any_castIlEET_RKNS_3anyE:
  468|   271k|{
  469|   271k|    auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
  470|   271k|#ifndef ANY_IMPL_NO_EXCEPTIONS
  471|   271k|    if(p == nullptr) throw bad_any_cast();
  ------------------
  |  Branch (471:8): [True: 0, False: 271k]
  ------------------
  472|   271k|#endif
  473|   271k|    return *p;
  474|   271k|}
_ZN4linb8any_castIKlEEPKT_PKNS_3anyE:
  510|   271k|{
  511|   271k|    using T = typename std::decay<ValueType>::type;
  512|       |
  513|   271k|#ifndef ANY_IMPL_NO_RTTI
  514|   271k|    if (operand && operand->is_typed(typeid(T)))
  ------------------
  |  Branch (514:9): [True: 271k, False: 0]
  |  Branch (514:20): [True: 271k, False: 0]
  ------------------
  515|       |#else
  516|       |    if (operand && operand->vtable == any::vtable_for_type<T>())
  517|       |#endif
  518|   271k|        return operand->cast<ValueType>();
  519|      0|    else
  520|      0|        return nullptr;
  521|   271k|}
_ZNK4linb3any4castIKlEEPKT_v:
  380|   271k|    {
  381|   271k|        return requires_allocation<typename std::decay<T>::type>::value?
  ------------------
  |  Branch (381:16): [Folded, False: 271k]
  ------------------
  382|      0|            reinterpret_cast<const T*>(storage.dynamic) :
  383|   271k|            reinterpret_cast<const T*>(&storage.stack);
  384|   271k|    }
_ZN4linb3anyC2IlvEEOT_:
  110|  1.42M|    {
  111|  1.42M|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|  1.42M|            "T shall satisfy the CopyConstructible requirements.");
  113|  1.42M|        this->construct(std::forward<ValueType>(value));
  114|  1.42M|    }
_ZN4linb3any9constructIlEEvOT_:
  439|  1.42M|    {
  440|  1.42M|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|  1.42M|        this->vtable = vtable_for_type<T>();
  443|       |
  444|  1.42M|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|  1.42M|    }
_ZN4linb3any15vtable_for_typeIlEEPNS0_11vtable_typeEv:
  333|  1.42M|    {
  334|  1.42M|        using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
  335|  1.42M|        static vtable_type table = {
  336|  1.42M|#ifndef ANY_IMPL_NO_RTTI
  337|  1.42M|            VTableType::type,
  338|  1.42M|#endif
  339|  1.42M|            VTableType::destroy,
  340|  1.42M|            VTableType::copy, VTableType::move,
  341|  1.42M|            VTableType::swap,
  342|  1.42M|        };
  343|  1.42M|        return &table;
  344|  1.42M|    }
_ZN4linb3any12vtable_stackIlE4typeEv:
  289|  1.77M|        {
  290|  1.77M|            return typeid(T);
  291|  1.77M|        }
_ZN4linb3any12vtable_stackIlE7destroyERNS0_13storage_unionE:
  295|  4.94M|        {
  296|  4.94M|            reinterpret_cast<T*>(&storage.stack)->~T();
  297|  4.94M|        }
_ZN4linb3any12vtable_stackIlE4copyERKNS0_13storage_unionERS3_:
  300|  1.70M|        {
  301|  1.70M|            new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
  302|  1.70M|        }
_ZN4linb3any12vtable_stackIlE4moveERNS0_13storage_unionES4_:
  305|  1.81M|        {
  306|       |            // one of the conditions for using vtable_stack is a nothrow move constructor,
  307|       |            // so this move constructor will never throw a exception.
  308|  1.81M|            new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
  309|  1.81M|            destroy(src);
  310|  1.81M|        }
_ZN4linb3any12vtable_stackIlE4swapERNS0_13storage_unionES4_:
  313|  26.3k|        {
  314|  26.3k|            storage_union tmp_storage;
  315|  26.3k|            move(rhs, tmp_storage);
  316|  26.3k|            move(lhs, rhs);
  317|  26.3k|            move(tmp_storage, lhs);
  318|  26.3k|        }
_ZN4linb3any12do_constructIllEENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|  1.42M|    {
  432|  1.42M|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|  1.42M|    }
_ZN4linb3anyaSERKS0_:
  129|   272k|    {
  130|   272k|        any(rhs).swap(*this);
  131|   272k|        return *this;
  132|   272k|    }
_ZN4linb3anyC2ERKS0_:
   78|  2.45M|        vtable(rhs.vtable)
   79|  2.45M|    {
   80|  2.45M|        if(!rhs.empty())
  ------------------
  |  Branch (80:12): [True: 2.45M, False: 636]
  ------------------
   81|  2.45M|        {
   82|  2.45M|            rhs.vtable->copy(rhs.storage, this->storage);
   83|  2.45M|        }
   84|  2.45M|    }
_ZN4linb3any4swapERS0_:
  183|   312k|    {
  184|   312k|        if(this->vtable != rhs.vtable)
  ------------------
  |  Branch (184:12): [True: 235k, False: 77.2k]
  ------------------
  185|   235k|        {
  186|   235k|            any tmp(std::move(rhs));
  187|       |
  188|       |            // move from *this to rhs.
  189|   235k|            rhs.vtable = this->vtable;
  190|   235k|            if(this->vtable != nullptr)
  ------------------
  |  Branch (190:16): [True: 235k, False: 0]
  ------------------
  191|   235k|            {
  192|   235k|                this->vtable->move(this->storage, rhs.storage);
  193|       |                //this->vtable = nullptr; -- unneeded, see below
  194|   235k|            }
  195|       |
  196|       |            // move from tmp (previously rhs) to *this.
  197|   235k|            this->vtable = tmp.vtable;
  198|   235k|            if(tmp.vtable != nullptr)
  ------------------
  |  Branch (198:16): [True: 205k, False: 30.0k]
  ------------------
  199|   205k|            {
  200|   205k|                tmp.vtable->move(tmp.storage, this->storage);
  201|   205k|                tmp.vtable = nullptr;
  202|   205k|            }
  203|   235k|        }
  204|  77.2k|        else // same types
  205|  77.2k|        {
  206|  77.2k|            if(this->vtable != nullptr)
  ------------------
  |  Branch (206:16): [True: 46.0k, False: 31.2k]
  ------------------
  207|  46.0k|                this->vtable->swap(this->storage, rhs.storage);
  208|  77.2k|        }
  209|   312k|    }
_ZN4linb3anyC2EOS0_:
   89|  2.02M|        vtable(rhs.vtable)
   90|  2.02M|    {
   91|  2.02M|        if(!rhs.empty())
  ------------------
  |  Branch (91:12): [True: 1.99M, False: 30.0k]
  ------------------
   92|  1.99M|        {
   93|  1.99M|            rhs.vtable->move(rhs.storage, this->storage);
   94|  1.99M|            rhs.vtable = nullptr;
   95|  1.99M|        }
   96|  2.02M|    }
_ZN4linb3anyaSEOS0_:
  139|  39.3k|    {
  140|  39.3k|        std::move(rhs).swap(*this);
  141|  39.3k|        return *this;
  142|  39.3k|    }
_ZN4linb3anyaSIlvEERS0_OT_:
  150|    864|    {
  151|    864|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  152|    864|            "T shall satisfy the CopyConstructible requirements.");
  153|    864|        any(std::forward<ValueType>(value)).swap(*this);
  154|    864|        return *this;
  155|    864|    }
_ZN4linb3anyaSIdvEERS0_OT_:
  150|    194|    {
  151|    194|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  152|    194|            "T shall satisfy the CopyConstructible requirements.");
  153|    194|        any(std::forward<ValueType>(value)).swap(*this);
  154|    194|        return *this;
  155|    194|    }
_ZN4linb3anyC2IdvEEOT_:
  110|    194|    {
  111|    194|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|    194|            "T shall satisfy the CopyConstructible requirements.");
  113|    194|        this->construct(std::forward<ValueType>(value));
  114|    194|    }
_ZN4linb3any9constructIdEEvOT_:
  439|    194|    {
  440|    194|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|    194|        this->vtable = vtable_for_type<T>();
  443|       |
  444|    194|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|    194|    }
_ZN4linb3any15vtable_for_typeIdEEPNS0_11vtable_typeEv:
  333|   268k|    {
  334|   268k|        using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
  335|   268k|        static vtable_type table = {
  336|   268k|#ifndef ANY_IMPL_NO_RTTI
  337|   268k|            VTableType::type,
  338|   268k|#endif
  339|   268k|            VTableType::destroy,
  340|   268k|            VTableType::copy, VTableType::move,
  341|   268k|            VTableType::swap,
  342|   268k|        };
  343|   268k|        return &table;
  344|   268k|    }
_ZN4linb3any12vtable_stackIdE4typeEv:
  289|  95.4k|        {
  290|  95.4k|            return typeid(T);
  291|  95.4k|        }
_ZN4linb3any12vtable_stackIdE7destroyERNS0_13storage_unionE:
  295|   312k|        {
  296|   312k|            reinterpret_cast<T*>(&storage.stack)->~T();
  297|   312k|        }
_ZN4linb3any12vtable_stackIdE4copyERKNS0_13storage_unionERS3_:
  300|  19.5k|        {
  301|  19.5k|            new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
  302|  19.5k|        }
_ZN4linb3any12vtable_stackIdE4moveERNS0_13storage_unionES4_:
  305|  25.0k|        {
  306|       |            // one of the conditions for using vtable_stack is a nothrow move constructor,
  307|       |            // so this move constructor will never throw a exception.
  308|  25.0k|            new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
  309|  25.0k|            destroy(src);
  310|  25.0k|        }
_ZN4linb3any12vtable_stackIdE4swapERNS0_13storage_unionES4_:
  313|  3.13k|        {
  314|  3.13k|            storage_union tmp_storage;
  315|  3.13k|            move(rhs, tmp_storage);
  316|  3.13k|            move(lhs, rhs);
  317|  3.13k|            move(tmp_storage, lhs);
  318|  3.13k|        }
_ZN4linb3any12do_constructIddEENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|    194|    {
  432|    194|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|    194|    }
_ZN4linb3anyC2IRKdvEEOT_:
  110|   268k|    {
  111|   268k|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|   268k|            "T shall satisfy the CopyConstructible requirements.");
  113|   268k|        this->construct(std::forward<ValueType>(value));
  114|   268k|    }
_ZN4linb3any9constructIRKdEEvOT_:
  439|   268k|    {
  440|   268k|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|   268k|        this->vtable = vtable_for_type<T>();
  443|       |
  444|   268k|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|   268k|    }
_ZN4linb3any12do_constructIRKddEENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|   268k|    {
  432|   268k|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|   268k|    }
_ZN4linb3anyC2IN7SafeAny12SimpleStringEvEEOT_:
  110|   380k|    {
  111|   380k|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|   380k|            "T shall satisfy the CopyConstructible requirements.");
  113|   380k|        this->construct(std::forward<ValueType>(value));
  114|   380k|    }
_ZN4linb3any9constructIN7SafeAny12SimpleStringEEEvOT_:
  439|   380k|    {
  440|   380k|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|   380k|        this->vtable = vtable_for_type<T>();
  443|       |
  444|   380k|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|   380k|    }
_ZN4linb3any15vtable_for_typeIN7SafeAny12SimpleStringEEEPNS0_11vtable_typeEv:
  333|   380k|    {
  334|   380k|        using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
  335|   380k|        static vtable_type table = {
  336|   380k|#ifndef ANY_IMPL_NO_RTTI
  337|   380k|            VTableType::type,
  338|   380k|#endif
  339|   380k|            VTableType::destroy,
  340|   380k|            VTableType::copy, VTableType::move,
  341|   380k|            VTableType::swap,
  342|   380k|        };
  343|   380k|        return &table;
  344|   380k|    }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4typeEv:
  289|  2.64M|        {
  290|  2.64M|            return typeid(T);
  291|  2.64M|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE7destroyERNS0_13storage_unionE:
  295|  1.84M|        {
  296|  1.84M|            reinterpret_cast<T*>(&storage.stack)->~T();
  297|  1.84M|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4copyERKNS0_13storage_unionERS5_:
  300|   734k|        {
  301|   734k|            new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
  302|   734k|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4moveERNS0_13storage_unionES6_:
  305|   729k|        {
  306|       |            // one of the conditions for using vtable_stack is a nothrow move constructor,
  307|       |            // so this move constructor will never throw a exception.
  308|   729k|            new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
  309|   729k|            destroy(src);
  310|   729k|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4swapERNS0_13storage_unionES6_:
  313|  16.5k|        {
  314|  16.5k|            storage_union tmp_storage;
  315|  16.5k|            move(rhs, tmp_storage);
  316|  16.5k|            move(lhs, rhs);
  317|  16.5k|            move(tmp_storage, lhs);
  318|  16.5k|        }
_ZN4linb3any12do_constructIN7SafeAny12SimpleStringES3_EENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|   380k|    {
  432|   380k|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|   380k|    }

_ZNK6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  5.44k|    {
 2192|  5.44k|        return has_value();
 2193|  5.44k|    }
_ZNK6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  10.8k|    {
 2197|  10.8k|        return contained.has_value();
 2198|  10.8k|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  10.8k|    {
  787|  10.8k|        return m_has_value;
  788|  10.8k|    }
_ZNK6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  6.95k|    {
 2192|  6.95k|        return has_value();
 2193|  6.95k|    }
_ZNK6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  17.8k|    {
 2197|  17.8k|        return contained.has_value();
 2198|  17.8k|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  17.8k|    {
  787|  17.8k|        return m_has_value;
  788|  17.8k|    }
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IdTnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIdOT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISB_E4typeESt10in_place_tEE5valuentsr3std7is_sameIS8_SG_EE5valuentsr3std7is_sameINS0_15unexpected_typeIS7_EESG_EE5valuesr3std14is_convertibleISC_dEE5valueEiE4typeELi0EEESC_:
 1927|   751k|    : contained( true )
 1928|   751k|    {
 1929|   751k|        contained.construct_value( std::forward<U>( value ) );
 1930|   751k|    }
_ZN6nonstd13expected_lite6detail9storage_tIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|   958k|        : storage_t_impl<T, E>( has_value )
  922|   958k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|   958k|        : m_has_value( has_value )
  674|   958k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOd:
  687|   751k|    {
  688|   751k|        new( &m_value ) value_type( std::move( e ) );
  689|   751k|    }
_ZN6nonstd13expected_lite15make_unexpectedIRA39_KcEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOS7_:
 1566|    166|{
 1567|    166|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|    166|}
_ZN6nonstd13expected_lite15unexpected_typeIPKcEC2IRA39_S2_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS3_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefIS9_E4typeESt10in_place_tEE5valuentsr3std7is_sameISD_S4_EE5valueEiE4typeELi0EEEOS9_:
 1237|    166|    : m_error( std::forward<E2>( error ) )
 1238|    166|    {}
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleIS7_OT_EE5valuesr3std14is_convertibleISE_S7_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISD_EE:
 1977|    166|    : contained( false )
 1978|    166|    {
 1979|    166|        contained.construct_error( std::move( error.error() ) );
 1980|    166|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOS8_:
  714|    332|    {
  715|    332|        new( &m_error ) error_type( std::move( e ) );
  716|    332|    }
_ZNR6nonstd13expected_lite15unexpected_typeIPKcE5errorEv:
 1334|  5.61k|    {
 1335|  5.61k|        return m_error;
 1336|  5.61k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|   958k|    ~storage_t_impl() {}
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IRdTnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIdOT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISC_E4typeESt10in_place_tEE5valuentsr3std7is_sameIS8_SH_EE5valuentsr3std7is_sameINS0_15unexpected_typeIS7_EESH_EE5valuesr3std14is_convertibleISD_dEE5valueEiE4typeELi0EEESD_:
 1927|   207k|    : contained( true )
 1928|   207k|    {
 1929|   207k|        contained.construct_value( std::forward<U>( value ) );
 1930|   207k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueERKd:
  682|   207k|    {
  683|   207k|        new( &m_value ) value_type( e );
  684|   207k|    }
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2EOS8_:
 1793|    166|    nsel_constexpr14 expected( expected &&      ) = default;
_ZN6nonstd13expected_lite6detail9storage_tIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2EOS9_:
  932|    166|        : storage_t_impl<T, E>( other.has_value() )
  933|    166|    {
  934|    166|        if ( this->has_value() ) this->construct_value( std::move( other.value() ) );
  ------------------
  |  Branch (934:14): [True: 0, False: 166]
  ------------------
  935|    166|        else                     this->construct_error( std::move( other.error() ) );
  936|    166|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  2.87M|    {
  787|  2.87M|        return m_has_value;
  788|  2.87M|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|   958k|    {
  742|   958k|        return m_value;
  743|   958k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
  771|    332|    {
  772|    332|        return m_error;
  773|    332|    }
_ZNR6nonstd13expected_lite15unexpected_typeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
 1334|  1.51k|    {
 1335|  1.51k|        return m_error;
 1336|  1.51k|    }
_ZNK6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|   958k|    {
 2192|   958k|        return has_value();
 2193|   958k|    }
_ZNK6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  2.87M|    {
 2197|  2.87M|        return contained.has_value();
 2198|  2.87M|    }
_ZNR6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|   958k|    {
 2211|   958k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 958k, False: 0]
  ------------------
 2212|   958k|            ? ( contained.value() )
 2213|   958k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|   958k|    }
_ZNR6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
 2241|    166|    {
 2242|       |        return assert( ! has_value() ), contained.error();
 2243|    166|    }
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|   958k|    {
 2038|   958k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 958k, False: 332]
  ------------------
 2039|    332|        else               contained.destruct_error();
 2040|   958k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|   958k|    {
  705|   958k|        m_value.~value_type();
  706|   958k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|    332|    {
  732|    332|        m_error.~error_type();
  733|    332|    }
_ZN6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IlTnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIlOT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISB_E4typeESt10in_place_tEE5valuentsr3std7is_sameIS8_SG_EE5valuentsr3std7is_sameINS0_15unexpected_typeIS7_EESG_EE5valuesr3std14is_convertibleISC_lEE5valueEiE4typeELi0EEESC_:
 1927|  4.75k|    : contained( true )
 1928|  4.75k|    {
 1929|  4.75k|        contained.construct_value( std::forward<U>( value ) );
 1930|  4.75k|    }
_ZN6nonstd13expected_lite6detail9storage_tIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  4.75k|        : storage_t_impl<T, E>( has_value )
  922|  4.75k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  4.75k|        : m_has_value( has_value )
  674|  4.75k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOl:
  687|  4.75k|    {
  688|  4.75k|        new( &m_value ) value_type( std::move( e ) );
  689|  4.75k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  4.75k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  14.2k|    {
  787|  14.2k|        return m_has_value;
  788|  14.2k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  4.75k|    {
  742|  4.75k|        return m_value;
  743|  4.75k|    }
_ZNK6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  4.75k|    {
 2192|  4.75k|        return has_value();
 2193|  4.75k|    }
_ZNK6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  14.2k|    {
 2197|  14.2k|        return contained.has_value();
 2198|  14.2k|    }
_ZNR6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  4.75k|    {
 2211|  4.75k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 4.75k, False: 0]
  ------------------
 2212|  4.75k|            ? ( contained.value() )
 2213|  4.75k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  4.75k|    }
_ZN6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  4.75k|    {
 2038|  4.75k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 4.75k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|  4.75k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  4.75k|    {
  705|  4.75k|        m_value.~value_type();
  706|  4.75k|    }
_ZN6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  5.44k|    {
 2038|  5.44k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 3.93k, False: 1.51k]
  ------------------
 2039|  1.51k|        else               contained.destruct_error();
 2040|  5.44k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  3.93k|    {
  705|  3.93k|        m_value.~value_type();
  706|  3.93k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|  1.51k|    {
  732|  1.51k|        m_error.~error_type();
  733|  1.51k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  5.44k|    ~storage_t_impl() {}
_ZN6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  6.95k|    {
 2038|  6.95k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 3.93k, False: 3.02k]
  ------------------
 2039|  3.02k|        else               contained.destruct_error();
 2040|  6.95k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  3.93k|    {
  705|  3.93k|        m_value.~value_type();
  706|  3.93k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|  3.02k|    {
  732|  3.02k|        m_error.~error_type();
  733|  3.02k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  6.95k|    ~storage_t_impl() {}
_ZNR6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  3.93k|    {
 2211|  3.93k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 3.93k, False: 0]
  ------------------
 2212|  3.93k|            ? ( contained.value() )
 2213|  3.93k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  3.93k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  3.93k|    {
  742|  3.93k|        return m_value;
  743|  3.93k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
  771|  1.51k|    {
  772|  1.51k|        return m_error;
  773|  1.51k|    }
_ZN6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IS3_TnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIS3_OT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISD_E4typeESt10in_place_tEE5valuentsr3std7is_sameISA_SI_EE5valuentsr3std7is_sameINS0_15unexpected_typeIS9_EESI_EE5valuesr3std14is_convertibleISE_S3_EE5valueEiE4typeELi0EEESE_:
 1927|  2.81k|    : contained( true )
 1928|  2.81k|    {
 1929|  2.81k|        contained.construct_value( std::forward<U>( value ) );
 1930|  2.81k|    }
_ZN6nonstd13expected_lite6detail9storage_tIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  5.23k|        : storage_t_impl<T, E>( has_value )
  922|  5.23k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  5.23k|        : m_has_value( has_value )
  674|  5.23k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOS4_:
  687|  2.81k|    {
  688|  2.81k|        new( &m_value ) value_type( std::move( e ) );
  689|  2.81k|    }
_ZN6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IS9_TnNSt9enable_ifIXaasr3std16is_constructibleIS9_OT_EE5valuesr3std14is_convertibleISE_S9_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISD_EE:
 1977|  1.51k|    : contained( false )
 1978|  1.51k|    {
 1979|  1.51k|        contained.construct_error( std::move( error.error() ) );
 1980|  1.51k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOSA_:
  714|  2.42k|    {
  715|  2.42k|        new( &m_error ) error_type( std::move( e ) );
  716|  2.42k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  5.23k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  5.23k|    {
  787|  5.23k|        return m_has_value;
  788|  5.23k|    }
_ZNK6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  5.23k|    {
 2197|  5.23k|        return contained.has_value();
 2198|  5.23k|    }
_ZN6nonstd13expected_lite15make_unexpectedIRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOSB_:
 1566|  1.51k|{
 1567|  1.51k|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|  1.51k|}
_ZN6nonstd13expected_lite15unexpected_typeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IRS7_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS7_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISC_E4typeESt10in_place_tEE5valuentsr3std7is_sameISG_S8_EE5valueEiE4typeELi0EEEOSC_:
 1237|  1.51k|    : m_error( std::forward<E2>( error ) )
 1238|  1.51k|    {}
_ZN6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  5.23k|    {
 2038|  5.23k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 2.81k, False: 2.42k]
  ------------------
 2039|  2.42k|        else               contained.destruct_error();
 2040|  5.23k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  2.81k|    {
  705|  2.81k|        m_value.~value_type();
  706|  2.81k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|  2.42k|    {
  732|  2.42k|        m_error.~error_type();
  733|  2.42k|    }
_ZNK6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_E9has_valueEv:
 2196|  1.42M|    {
 2197|  1.42M|        return contained.has_value();
 2198|  1.42M|    }
_ZNK6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EcvbEv:
 2191|   474k|    {
 2192|   474k|        return has_value();
 2193|   474k|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E9has_valueEv:
  786|  1.42M|    {
  787|  1.42M|        return m_has_value;
  788|  1.42M|    }
_ZN6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EC2IS7_TnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIS7_OT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISB_E4typeESt10in_place_tEE5valuentsr3std7is_sameIS8_SG_EE5valuentsr3std7is_sameINS0_15unexpected_typeIS7_EESG_EE5valuesr3std14is_convertibleISC_S7_EE5valueEiE4typeELi0EEESC_:
 1927|   474k|    : contained( true )
 1928|   474k|    {
 1929|   474k|        contained.construct_value( std::forward<U>( value ) );
 1930|   474k|    }
_ZN6nonstd13expected_lite6detail9storage_tINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_Lb1ELb1EEC2Eb:
  921|   474k|        : storage_t_impl<T, E>( has_value )
  922|   474k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EC2Eb:
  673|   474k|        : m_has_value( has_value )
  674|   474k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E15construct_valueEOS8_:
  687|   474k|    {
  688|   474k|        new( &m_value ) value_type( std::move( e ) );
  689|   474k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_ED2Ev:
  670|   474k|    ~storage_t_impl() {}
_ZN6nonstd13expected_lite15make_unexpectedIPKcEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOS6_:
 1566|  5.37k|{
 1567|  5.37k|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|  5.37k|}
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEv:
  677|  3.93k|    {
  678|  3.93k|        new( &m_value ) value_type();
  679|  3.93k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOS9_:
  714|  1.51k|    {
  715|  1.51k|        new( &m_error ) error_type( std::move( e ) );
  716|  1.51k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E5valueEv:
  741|   474k|    {
  742|   474k|        return m_value;
  743|   474k|    }
_ZNR6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_E5valueEv:
 2210|   474k|    {
 2211|   474k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 474k, False: 0]
  ------------------
 2212|   474k|            ? ( contained.value() )
 2213|   474k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|   474k|    }
_ZN6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_ED2Ev:
 2037|   474k|    {
 2038|   474k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 474k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|   474k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E14destruct_valueEv:
  704|   474k|    {
  705|   474k|        m_value.~value_type();
  706|   474k|    }
_ZN6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IS3_TnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIS3_OT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISD_E4typeESt10in_place_tEE5valuentsr3std7is_sameISA_SI_EE5valuentsr3std7is_sameINS0_15unexpected_typeIS9_EESI_EE5valuesr3std14is_convertibleISE_S3_EE5valueEiE4typeELi0EEESE_:
 1927|  16.9k|    : contained( true )
 1928|  16.9k|    {
 1929|  16.9k|        contained.construct_value( std::forward<U>( value ) );
 1930|  16.9k|    }
_ZN6nonstd13expected_lite6detail9storage_tIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  16.9k|        : storage_t_impl<T, E>( has_value )
  922|  16.9k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  16.9k|        : m_has_value( has_value )
  674|  16.9k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOS4_:
  687|  16.9k|    {
  688|  16.9k|        new( &m_value ) value_type( std::move( e ) );
  689|  16.9k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  16.9k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  50.8k|    {
  787|  50.8k|        return m_has_value;
  788|  50.8k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  16.9k|    {
  742|  16.9k|        return m_value;
  743|  16.9k|    }
_ZNK6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  16.9k|    {
 2192|  16.9k|        return has_value();
 2193|  16.9k|    }
_ZNK6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  50.8k|    {
 2197|  50.8k|        return contained.has_value();
 2198|  50.8k|    }
_ZNR6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  16.9k|    {
 2211|  16.9k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 16.9k, False: 0]
  ------------------
 2212|  16.9k|            ? ( contained.value() )
 2213|  16.9k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  16.9k|    }
_ZN6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  16.9k|    {
 2038|  16.9k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 16.9k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|  16.9k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  16.9k|    {
  705|  16.9k|        m_value.~value_type();
  706|  16.9k|    }
_ZN6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IbTnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIbOT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISB_E4typeESt10in_place_tEE5valuentsr3std7is_sameIS8_SG_EE5valuentsr3std7is_sameINS0_15unexpected_typeIS7_EESG_EE5valuesr3std14is_convertibleISC_bEE5valueEiE4typeELi0EEESC_:
 1927|  5.35k|    : contained( true )
 1928|  5.35k|    {
 1929|  5.35k|        contained.construct_value( std::forward<U>( value ) );
 1930|  5.35k|    }
_ZN6nonstd13expected_lite6detail9storage_tIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  5.35k|        : storage_t_impl<T, E>( has_value )
  922|  5.35k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  5.35k|        : m_has_value( has_value )
  674|  5.35k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOb:
  687|  5.35k|    {
  688|  5.35k|        new( &m_value ) value_type( std::move( e ) );
  689|  5.35k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  5.35k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  16.0k|    {
  787|  16.0k|        return m_has_value;
  788|  16.0k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  5.35k|    {
  742|  5.35k|        return m_value;
  743|  5.35k|    }
_ZNK6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  5.35k|    {
 2192|  5.35k|        return has_value();
 2193|  5.35k|    }
_ZNK6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  16.0k|    {
 2197|  16.0k|        return contained.has_value();
 2198|  16.0k|    }
_ZNR6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  5.35k|    {
 2211|  5.35k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 5.35k, False: 0]
  ------------------
 2212|  5.35k|            ? ( contained.value() )
 2213|  5.35k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  5.35k|    }
_ZN6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  5.35k|    {
 2038|  5.35k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 5.35k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|  5.35k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  5.35k|    {
  705|  5.35k|        m_value.~value_type();
  706|  5.35k|    }
_ZN6nonstd13expected_lite15make_unexpectedIRA13_KcEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOS7_:
 1566|     72|{
 1567|     72|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|     72|}
_ZN6nonstd13expected_lite15unexpected_typeIPKcEC2IRA13_S2_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS3_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefIS9_E4typeESt10in_place_tEE5valuentsr3std7is_sameISD_S4_EE5valueEiE4typeELi0EEEOS9_:
 1237|     72|    : m_error( std::forward<E2>( error ) )
 1238|     72|    {}
_ZN6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleISF_OT_EE5valuesr3std14is_convertibleISM_SF_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISL_EE:
 1977|  3.02k|    : contained( false )
 1978|  3.02k|    {
 1979|  3.02k|        contained.construct_error( std::move( error.error() ) );
 1980|  3.02k|    }
_ZN6nonstd13expected_lite6detail9storage_tISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  6.95k|        : storage_t_impl<T, E>( has_value )
  922|  6.95k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  6.95k|        : m_has_value( has_value )
  674|  6.95k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOSG_:
  714|  3.02k|    {
  715|  3.02k|        new( &m_error ) error_type( std::move( e ) );
  716|  3.02k|    }
script_parser.cpp:_ZN6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IZNS3_11ParseScriptERKSF_E3$_0TnNSt9enable_ifIXaaaaaaaasr3std16is_constructibleIS9_OT_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISM_E4typeESt10in_place_tEE5valuentsr3std7is_sameISG_SR_EE5valuentsr3std7is_sameINS0_15unexpected_typeISF_EESR_EE5valuesr3std14is_convertibleISN_S9_EE5valueEiE4typeELi0EEESN_:
 1927|  3.93k|    : contained( true )
 1928|  3.93k|    {
 1929|  3.93k|        contained.construct_value( std::forward<U>( value ) );
 1930|  3.93k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOSA_:
  687|  3.93k|    {
  688|  3.93k|        new( &m_value ) value_type( std::move( e ) );
  689|  3.93k|    }
_ZN6nonstd13expected_lite15unexpected_typeIPKcEC2IS3_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS3_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefIS7_E4typeESt10in_place_tEE5valuentsr3std7is_sameISB_S4_EE5valueEiE4typeELi0EEEOS7_:
 1237|  5.37k|    : m_error( std::forward<E2>( error ) )
 1238|  5.37k|    {}
_ZN6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleIS9_OT_EE5valuesr3std14is_convertibleISG_S9_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISF_EE:
 1977|    911|    : contained( false )
 1978|    911|    {
 1979|    911|        contained.construct_error( std::move( error.error() ) );
 1980|    911|    }
_ZN6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleIS8_OT_EE5valuesr3std14is_convertibleISF_S8_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISE_EE:
 1977|  1.51k|    : contained( false )
 1978|  1.51k|    {
 1979|  1.51k|        contained.construct_error( std::move( error.error() ) );
 1980|  1.51k|    }
_ZN6nonstd13expected_lite6detail9storage_tISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  5.44k|        : storage_t_impl<T, E>( has_value )
  922|  5.44k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  5.44k|        : m_has_value( has_value )
  674|  5.44k|    {}
_ZN6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2ILb1ETnNSt9enable_ifIXT_EiE4typeELi0EEEv:
 1787|  3.93k|    : contained( true )
 1788|  3.93k|    {
 1789|  3.93k|        contained.construct_value();
 1790|  3.93k|    }
_ZNR6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
 2241|  1.51k|    {
 2242|       |        return assert( ! has_value() ), contained.error();
 2243|  1.51k|    }

_ZN2BT21BehaviorTreeExceptionC2IJNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEEDpRKT_:
   33|  6.07k|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|  6.07k|  {}
_ZNK2BT21BehaviorTreeException4whatEv:
   37|  6.28k|  {
   38|  6.28k|    return message_.c_str();
   39|  6.28k|  }
_ZN2BT12RuntimeErrorC2IJNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEEDpRKT_:
   67|  6.07k|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|  6.07k|  {}
_ZN2BT12RuntimeErrorC2IJA42_cEEEDpRKT_:
   67|      2|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      2|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA42_cEEEDpRKT_:
   33|      2|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      2|  {}
_ZN2BT12RuntimeErrorC2IJA33_cEEEDpRKT_:
   67|      3|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      3|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA33_cEEEDpRKT_:
   33|      3|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      3|  {}
_ZN2BT12RuntimeErrorC2IJA31_cEEEDpRKT_:
   67|      1|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      1|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA31_cEEEDpRKT_:
   33|      1|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      1|  {}
_ZN2BT12RuntimeErrorC2IJA47_cEEEDpRKT_:
   67|     40|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|     40|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA47_cEEEDpRKT_:
   33|     40|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|     40|  {}
_ZN2BT12RuntimeErrorC2IJA63_cEEEDpRKT_:
   67|      6|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      6|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA63_cEEEDpRKT_:
   33|      6|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      6|  {}
_ZN2BT12RuntimeErrorC2IJA35_cEEEDpRKT_:
   67|      5|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      5|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA35_cEEEDpRKT_:
   33|      5|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      5|  {}
_ZN2BT12RuntimeErrorC2IJA74_cEEEDpRKT_:
   67|      6|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      6|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA74_cEEEDpRKT_:
   33|      6|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      6|  {}
_ZN2BT12RuntimeErrorC2IJA79_cEEEDpRKT_:
   67|    125|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|    125|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA79_cEEEDpRKT_:
   33|    125|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|    125|  {}
_ZN2BT12RuntimeErrorC2IJA24_cEEEDpRKT_:
   67|     28|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|     28|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA24_cEEEDpRKT_:
   33|     28|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|     28|  {}

_ZN2BT3Ast19ExprUnaryArithmeticC2ENS1_4op_tESt10shared_ptrINS0_8ExprBaseEE:
  118|  17.0k|  explicit ExprUnaryArithmetic(op_t op, expr_ptr e) : op(op), rhs(std::move(e))
  119|  17.0k|  {}
_ZN2BT3Ast8ExprBaseD2Ev:
   57|  9.61M|  virtual ~ExprBase() = default;
_ZNK2BT3Ast19ExprUnaryArithmetic8evaluateERNS0_11EnvironmentE:
  122|  2.96k|  {
  123|  2.96k|    auto rhs_v = rhs->evaluate(env);
  124|  2.96k|    if(rhs_v.isNumber())
  ------------------
  |  Branch (124:8): [True: 2.92k, False: 40]
  ------------------
  125|  2.92k|    {
  126|  2.92k|      const double rv = rhs_v.cast<double>();
  127|  2.92k|      switch(op)
  ------------------
  |  Branch (127:14): [True: 2.91k, False: 11]
  ------------------
  128|  2.92k|      {
  129|    856|        case negate:
  ------------------
  |  Branch (129:9): [True: 856, False: 2.07k]
  ------------------
  130|    856|          return Any(-rv);
  131|    849|        case complement:
  ------------------
  |  Branch (131:9): [True: 849, False: 2.07k]
  ------------------
  132|    849|          if(rv > static_cast<double>(std::numeric_limits<int64_t>::max()) ||
  ------------------
  |  Branch (132:14): [True: 1, False: 848]
  ------------------
  133|    848|             rv < static_cast<double>(std::numeric_limits<int64_t>::min()))
  ------------------
  |  Branch (133:14): [True: 1, False: 847]
  ------------------
  134|      2|          {
  135|      2|            throw RuntimeError("Number out of range for bitwise operation");
  136|      2|          }
  137|    847|          return Any(static_cast<double>(~static_cast<int64_t>(rv)));
  138|  1.21k|        case logical_not:
  ------------------
  |  Branch (138:9): [True: 1.21k, False: 1.71k]
  ------------------
  139|  1.21k|          return Any(static_cast<double>(!static_cast<bool>(rv)));
  140|  2.92k|      }
  141|  2.92k|    }
  142|     40|    else if(rhs_v.isString())
  ------------------
  |  Branch (142:13): [True: 3, False: 37]
  ------------------
  143|      3|    {
  144|      3|      throw RuntimeError("Invalid operator for std::string");
  145|      3|    }
  146|     37|    throw RuntimeError("ExprUnaryArithmetic: undefined");
  147|  2.96k|  }
_ZN2BT3Ast11ExprLiteralC2ENS_3AnyE:
   71|  1.78M|  ExprLiteral(Any v) : value(v)
   72|  1.78M|  {}
_ZNK2BT3Ast11ExprLiteral8evaluateERNS0_11EnvironmentE:
   75|   264k|  {
   76|   264k|    return value;
   77|   264k|  }
_ZN2BT3Ast8ExprNameC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   84|  7.66M|  explicit ExprName(std::string n) : name(std::move(n))
   85|  7.66M|  {}
_ZNK2BT3Ast8ExprName8evaluateERNS0_11EnvironmentE:
   88|   112k|  {
   89|       |    //search first in the enums table
   90|   112k|    if(env.enums)
  ------------------
  |  Branch (90:8): [True: 112k, False: 0]
  ------------------
   91|   112k|    {
   92|   112k|      auto enum_ptr = env.enums->find(name);
   93|   112k|      if(enum_ptr != env.enums->end())
  ------------------
  |  Branch (93:10): [True: 0, False: 112k]
  ------------------
   94|      0|      {
   95|      0|        return Any(double(enum_ptr->second));
   96|      0|      }
   97|   112k|    }
   98|       |    // search now in the variables table
   99|   112k|    auto any_ref = env.vars->getAnyLocked(name);
  100|   112k|    if(!any_ref)
  ------------------
  |  Branch (100:8): [True: 524, False: 111k]
  ------------------
  101|    524|    {
  102|    524|      throw RuntimeError(StrCat("Variable not found: ", name));
  103|    524|    }
  104|   111k|    return *any_ref.get();
  105|   112k|  }
_ZN2BT3Ast14ExprAssignmentC2ESt10shared_ptrINS0_8ExprBaseEENS1_4op_tES4_:
  507|  63.0k|    : op(op), lhs(std::move(_lhs)), rhs(std::move(_rhs))
  508|  63.0k|  {}
_ZNK2BT3Ast14ExprAssignment8evaluateERNS0_11EnvironmentE:
  511|  24.7k|  {
  512|  24.7k|    auto varname = dynamic_cast<ExprName*>(lhs.get());
  513|  24.7k|    if(!varname)
  ------------------
  |  Branch (513:8): [True: 40, False: 24.7k]
  ------------------
  514|     40|    {
  515|     40|      throw RuntimeError("Assignment left operand not a blackboard entry");
  516|     40|    }
  517|  24.7k|    const auto& key = varname->name;
  518|       |
  519|  24.7k|    auto entry = env.vars->getEntry(key);
  520|  24.7k|    if(!entry)
  ------------------
  |  Branch (520:8): [True: 9.49k, False: 15.2k]
  ------------------
  521|  9.49k|    {
  522|       |      // variable doesn't exist, create it if using operator assign_create
  523|  9.49k|      if(op == assign_create)
  ------------------
  |  Branch (523:10): [True: 9.44k, False: 47]
  ------------------
  524|  9.44k|      {
  525|  9.44k|        env.vars->createEntry(key, PortInfo());
  526|  9.44k|        entry = env.vars->getEntry(key);
  527|  9.44k|        if(!entry)
  ------------------
  |  Branch (527:12): [True: 0, False: 9.44k]
  ------------------
  528|      0|        {
  529|      0|          throw LogicError("Bug: report");
  530|      0|        }
  531|  9.44k|      }
  532|     47|      else
  533|     47|      {
  534|       |        // fail otherwise
  535|     47|        auto msg = StrCat("The blackboard entry [", key,
  536|     47|                          "] doesn't exist, yet.\n"
  537|     47|                          "If you want to create a new one, "
  538|     47|                          "use the operator "
  539|     47|                          "[:=] instead of [=]");
  540|     47|        throw RuntimeError(msg);
  541|     47|      }
  542|  9.49k|    }
  543|  24.6k|    auto value = rhs->evaluate(env);
  544|       |
  545|  24.6k|    std::scoped_lock lock(entry->entry_mutex);
  546|  24.6k|    auto* dst_ptr = &entry->value;
  547|       |
  548|  24.6k|    auto errorPrefix = [dst_ptr, &key]() {
  549|  24.6k|      return StrCat("Error assigning a value to entry [", key, "] with type [",
  550|  24.6k|                    BT::demangle(dst_ptr->type()), "]. ");
  551|  24.6k|    };
  552|       |
  553|  24.6k|    if(value.empty())
  ------------------
  |  Branch (553:8): [True: 42, False: 24.6k]
  ------------------
  554|     42|    {
  555|     42|      throw RuntimeError(ErrorNotInit("right", opStr()));
  556|     42|    }
  557|       |
  558|  24.6k|    if(op == assign_create || op == assign_existing)
  ------------------
  |  Branch (558:8): [True: 15.3k, False: 9.25k]
  |  Branch (558:31): [True: 1.73k, False: 7.51k]
  ------------------
  559|  10.6k|    {
  560|       |      // the very fist assignment can come from any type.
  561|       |      // In the future, type check will be done by Any::copyInto
  562|  10.6k|      if(dst_ptr->empty() && entry->info.type() == typeid(AnyTypeAllowed))
  ------------------
  |  Branch (562:10): [True: 8.23k, False: 2.41k]
  |  Branch (562:10): [True: 8.23k, False: 2.41k]
  |  Branch (562:30): [True: 8.23k, False: 0]
  ------------------
  563|  8.23k|      {
  564|  8.23k|        *dst_ptr = value;
  565|  8.23k|      }
  566|  2.41k|      else if(value.isString() && !dst_ptr->isString())
  ------------------
  |  Branch (566:15): [True: 1.52k, False: 882]
  |  Branch (566:35): [True: 661, False: 868]
  ------------------
  567|    661|      {
  568|       |        // special case: string to other type.
  569|       |        // Check if we can use the StringConverter
  570|    661|        auto const str = value.cast<std::string>();
  571|    661|        const auto* entry_info = env.vars->entryInfo(key);
  572|       |
  573|    661|        if(auto converter = entry_info->converter())
  ------------------
  |  Branch (573:17): [True: 0, False: 661]
  ------------------
  574|      0|        {
  575|      0|          *dst_ptr = converter(str);
  576|      0|        }
  577|    661|        else if(dst_ptr->isNumber())
  ------------------
  |  Branch (577:17): [True: 661, False: 0]
  ------------------
  578|    661|        {
  579|    661|          auto num_value = StringToDouble(value, env);
  580|    661|          *dst_ptr = Any(num_value);
  581|    661|        }
  582|      0|        else
  583|      0|        {
  584|      0|          auto msg = StrCat(errorPrefix(),
  585|      0|                            "\nThe right operand is a string, "
  586|      0|                            "can't convert to ",
  587|      0|                            demangle(dst_ptr->type()));
  588|      0|          throw RuntimeError(msg);
  589|      0|        }
  590|    661|      }
  591|  1.75k|      else
  592|  1.75k|      {
  593|  1.75k|        try
  594|  1.75k|        {
  595|  1.75k|          value.copyInto(*dst_ptr);
  596|  1.75k|        }
  597|  1.75k|        catch(std::exception&)
  598|  1.75k|        {
  599|     55|          auto msg = StrCat(errorPrefix(), "\nThe right operand has type [",
  600|     55|                            BT::demangle(value.type()), "] and can't be converted to [",
  601|     55|                            BT::demangle(dst_ptr->type()), "]");
  602|     55|          throw RuntimeError(msg);
  603|     55|        }
  604|  1.75k|      }
  605|  10.5k|      entry->sequence_id++;
  606|  10.5k|      entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  607|  10.5k|      return *dst_ptr;
  608|  10.6k|    }
  609|       |
  610|  13.9k|    if(dst_ptr->empty())
  ------------------
  |  Branch (610:8): [True: 4, False: 13.9k]
  ------------------
  611|      4|    {
  612|      4|      throw RuntimeError(ErrorNotInit("left", opStr()));
  613|      4|    }
  614|       |
  615|       |    // temporary use
  616|  13.9k|    Any temp_variable = *dst_ptr;
  617|       |
  618|  13.9k|    if(value.isNumber())
  ------------------
  |  Branch (618:8): [True: 1.83k, False: 12.1k]
  ------------------
  619|  1.83k|    {
  620|  1.83k|      if(!temp_variable.isNumber())
  ------------------
  |  Branch (620:10): [True: 6, False: 1.82k]
  ------------------
  621|      6|      {
  622|      6|        throw RuntimeError("This Assignment operator can't be used "
  623|      6|                           "with a non-numeric type");
  624|      6|      }
  625|       |
  626|  1.82k|      auto lv = temp_variable.cast<double>();
  627|  1.82k|      auto rv = value.cast<double>();
  628|  1.82k|      switch(op)
  629|  1.82k|      {
  630|    516|        case assign_plus:
  ------------------
  |  Branch (630:9): [True: 516, False: 1.31k]
  ------------------
  631|    516|          temp_variable = Any(lv + rv);
  632|    516|          break;
  633|    457|        case assign_minus:
  ------------------
  |  Branch (633:9): [True: 457, False: 1.37k]
  ------------------
  634|    457|          temp_variable = Any(lv - rv);
  635|    457|          break;
  636|    461|        case assign_times:
  ------------------
  |  Branch (636:9): [True: 461, False: 1.36k]
  ------------------
  637|    461|          temp_variable = Any(lv * rv);
  638|    461|          break;
  639|    391|        case assign_div:
  ------------------
  |  Branch (639:9): [True: 391, False: 1.43k]
  ------------------
  640|    391|          temp_variable = Any(lv / rv);
  641|    391|          break;
  642|      0|        default: {
  ------------------
  |  Branch (642:9): [True: 0, False: 1.82k]
  ------------------
  643|      0|        }
  644|  1.82k|      }
  645|  1.82k|    }
  646|  12.1k|    else if(value.isString())
  ------------------
  |  Branch (646:13): [True: 5.68k, False: 6.45k]
  ------------------
  647|  5.68k|    {
  648|  5.68k|      if(op == assign_plus)
  ------------------
  |  Branch (648:10): [True: 5.67k, False: 5]
  ------------------
  649|  5.67k|      {
  650|  5.67k|        auto lv = temp_variable.cast<std::string>();
  651|  5.67k|        auto rv = value.cast<std::string>();
  652|  5.67k|        temp_variable = Any(lv + rv);
  653|  5.67k|      }
  654|      5|      else
  655|      5|      {
  656|      5|        throw RuntimeError("Operator not supported for strings");
  657|      5|      }
  658|  5.68k|    }
  659|       |
  660|  13.9k|    temp_variable.copyInto(*dst_ptr);
  661|  13.9k|    entry->sequence_id++;
  662|  13.9k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  663|  13.9k|    return *dst_ptr;
  664|  13.9k|  }
_ZN2BT3Ast12ErrorNotInitB5cxx11EPKcS2_:
   62|     69|{
   63|     69|  return StrCat("The ", side, " operand of the operator [", op_str,
   64|     69|                "] is not initialized");
   65|     69|}
_ZNK2BT3Ast14ExprAssignment5opStrEv:
  485|     46|  {
  486|     46|    switch(op)
  ------------------
  |  Branch (486:12): [True: 46, False: 0]
  ------------------
  487|     46|    {
  488|     24|      case assign_create:
  ------------------
  |  Branch (488:7): [True: 24, False: 22]
  ------------------
  489|     24|        return ":=";
  490|     18|      case assign_existing:
  ------------------
  |  Branch (490:7): [True: 18, False: 28]
  ------------------
  491|     18|        return "=";
  492|      1|      case assign_plus:
  ------------------
  |  Branch (492:7): [True: 1, False: 45]
  ------------------
  493|      1|        return "+=";
  494|      1|      case assign_minus:
  ------------------
  |  Branch (494:7): [True: 1, False: 45]
  ------------------
  495|      1|        return "-=";
  496|      2|      case assign_times:
  ------------------
  |  Branch (496:7): [True: 2, False: 44]
  ------------------
  497|      2|        return "*=";
  498|      0|      case assign_div:
  ------------------
  |  Branch (498:7): [True: 0, False: 46]
  ------------------
  499|      0|        return "/=";
  500|     46|    }
  501|      0|    return "";
  502|     46|  }
_ZN2BT3Ast14StringToDoubleERKNS_3AnyERKNS0_11EnvironmentE:
   32|   207k|{
   33|   207k|  const auto str = value.cast<std::string>();
   34|   207k|  if(str == "true")
  ------------------
  |  Branch (34:6): [True: 194, False: 207k]
  ------------------
   35|    194|  {
   36|    194|    return 1.0;
   37|    194|  }
   38|   207k|  if(str == "false")
  ------------------
  |  Branch (38:6): [True: 194, False: 207k]
  ------------------
   39|    194|  {
   40|    194|    return 0.0;
   41|    194|  }
   42|   207k|  if(env.enums)
  ------------------
  |  Branch (42:6): [True: 207k, False: 0]
  ------------------
   43|   207k|  {
   44|   207k|    auto it = env.enums->find(str);
   45|   207k|    if(it != env.enums->end())
  ------------------
  |  Branch (45:8): [True: 0, False: 207k]
  ------------------
   46|      0|    {
   47|      0|      return it->second;
   48|      0|    }
   49|   207k|  }
   50|   207k|  return value.cast<double>();
   51|   207k|}
_ZZNK2BT3Ast14ExprAssignment8evaluateERNS0_11EnvironmentEENKUlvE_clB5cxx11Ev:
  548|     55|    auto errorPrefix = [dst_ptr, &key]() {
  549|     55|      return StrCat("Error assigning a value to entry [", key, "] with type [",
  550|     55|                    BT::demangle(dst_ptr->type()), "]. ");
  551|     55|    };
_ZN2BT3Ast6ExprIfC2ESt10shared_ptrINS0_8ExprBaseEES4_S4_:
  453|  2.92k|    : condition(std::move(condition)), then(std::move(then)), else_(std::move(else_))
  454|  2.92k|  {}
_ZNK2BT3Ast6ExprIf8evaluateERNS0_11EnvironmentE:
  457|    656|  {
  458|    656|    const auto& v = condition->evaluate(env);
  459|    656|    bool valid = (v.isType<SimpleString>() && v.cast<SimpleString>().size() > 0) ||
  ------------------
  |  Branch (459:19): [True: 0, False: 656]
  |  Branch (459:47): [True: 0, False: 0]
  ------------------
  460|    646|                 (v.cast<double>() != 0.0);
  ------------------
  |  Branch (460:18): [True: 274, False: 372]
  ------------------
  461|    656|    if(valid)
  ------------------
  |  Branch (461:8): [True: 271, False: 385]
  ------------------
  462|    271|    {
  463|    271|      return then->evaluate(env);
  464|    271|    }
  465|    385|    else
  466|    385|    {
  467|    385|      return else_->evaluate(env);
  468|    385|    }
  469|    656|  }
_ZNK2BT3Ast14ExprComparison8evaluateERNS0_11EnvironmentE:
  352|  13.6k|  {
  353|  13.6k|    auto SwitchImpl = [&](const auto& lv, const auto& rv, op_t op) {
  354|  13.6k|      switch(op)
  355|  13.6k|      {
  356|  13.6k|        case equal:
  357|  13.6k|          if(!IsSame(lv, rv))
  358|  13.6k|            return false;
  359|  13.6k|          break;
  360|  13.6k|        case not_equal:
  361|  13.6k|          if(IsSame(lv, rv))
  362|  13.6k|            return false;
  363|  13.6k|          break;
  364|  13.6k|        case less:
  365|  13.6k|          if(lv >= rv)
  366|  13.6k|            return false;
  367|  13.6k|          break;
  368|  13.6k|        case greater:
  369|  13.6k|          if(lv <= rv)
  370|  13.6k|            return false;
  371|  13.6k|          break;
  372|  13.6k|        case less_equal:
  373|  13.6k|          if(lv > rv)
  374|  13.6k|            return false;
  375|  13.6k|          break;
  376|  13.6k|        case greater_equal:
  377|  13.6k|          if(lv < rv)
  378|  13.6k|            return false;
  379|  13.6k|          break;
  380|  13.6k|      }
  381|  13.6k|      return true;
  382|  13.6k|    };
  383|       |
  384|  13.6k|    auto lhs_v = operands[0]->evaluate(env);
  385|   248k|    for(auto i = 0u; i != ops.size(); ++i)
  ------------------
  |  Branch (385:22): [True: 243k, False: 4.76k]
  ------------------
  386|   243k|    {
  387|   243k|      auto rhs_v = operands[i + 1]->evaluate(env);
  388|       |
  389|   243k|      if(lhs_v.empty())
  ------------------
  |  Branch (389:10): [True: 8, False: 243k]
  ------------------
  390|      8|      {
  391|      8|        throw RuntimeError(ErrorNotInit("left", opStr(ops[i])));
  392|      8|      }
  393|   243k|      if(rhs_v.empty())
  ------------------
  |  Branch (393:10): [True: 2, False: 243k]
  ------------------
  394|      2|      {
  395|      2|        throw RuntimeError(ErrorNotInit("right", opStr(ops[i])));
  396|      2|      }
  397|   243k|      const Any False(0.0);
  398|       |
  399|   243k|      if(lhs_v.isNumber() && rhs_v.isNumber())
  ------------------
  |  Branch (399:10): [True: 130k, False: 112k]
  |  Branch (399:30): [True: 27.0k, False: 103k]
  ------------------
  400|  27.0k|      {
  401|  27.0k|        auto lv = lhs_v.cast<double>();
  402|  27.0k|        auto rv = rhs_v.cast<double>();
  403|  27.0k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (403:12): [True: 1.23k, False: 25.8k]
  ------------------
  404|  1.23k|        {
  405|  1.23k|          return False;
  406|  1.23k|        }
  407|  27.0k|      }
  408|   216k|      else if(lhs_v.isString() && rhs_v.isString())
  ------------------
  |  Branch (408:15): [True: 112k, False: 104k]
  |  Branch (408:35): [True: 8.46k, False: 103k]
  ------------------
  409|  8.46k|      {
  410|  8.46k|        auto lv = lhs_v.cast<SimpleString>();
  411|  8.46k|        auto rv = rhs_v.cast<SimpleString>();
  412|  8.46k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (412:12): [True: 4.11k, False: 4.35k]
  ------------------
  413|  4.11k|        {
  414|  4.11k|          return False;
  415|  4.11k|        }
  416|  8.46k|      }
  417|   207k|      else if(lhs_v.isString() && rhs_v.isNumber())
  ------------------
  |  Branch (417:15): [True: 103k, False: 104k]
  |  Branch (417:35): [True: 103k, False: 0]
  ------------------
  418|   103k|      {
  419|   103k|        auto lv = StringToDouble(lhs_v, env);
  420|   103k|        auto rv = rhs_v.cast<double>();
  421|   103k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (421:12): [True: 1.48k, False: 102k]
  ------------------
  422|  1.48k|        {
  423|  1.48k|          return False;
  424|  1.48k|        }
  425|   103k|      }
  426|   104k|      else if(lhs_v.isNumber() && rhs_v.isString())
  ------------------
  |  Branch (426:15): [True: 103k, False: 756]
  |  Branch (426:35): [True: 103k, False: 0]
  ------------------
  427|   103k|      {
  428|   103k|        auto lv = lhs_v.cast<double>();
  429|   103k|        auto rv = StringToDouble(rhs_v, env);
  430|   103k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (430:12): [True: 1.24k, False: 102k]
  ------------------
  431|  1.24k|        {
  432|  1.24k|          return False;
  433|  1.24k|        }
  434|   103k|      }
  435|    756|      else
  436|    756|      {
  437|    756|        throw RuntimeError(StrCat("Can't mix different types in Comparison. "
  438|    756|                                  "Left operand [",
  439|    756|                                  BT::demangle(lhs_v.type()), "] right operand [",
  440|    756|                                  BT::demangle(rhs_v.type()), "]"));
  441|    756|      }
  442|   234k|      lhs_v = rhs_v;
  443|   234k|    }
  444|  4.76k|    return Any(1.0);
  445|  13.6k|  }
_ZNK2BT3Ast14ExprComparison5opStrENS1_4op_tE:
  329|     10|  {
  330|     10|    switch(op)
  ------------------
  |  Branch (330:12): [True: 10, False: 0]
  ------------------
  331|     10|    {
  332|      0|      case equal:
  ------------------
  |  Branch (332:7): [True: 0, False: 10]
  ------------------
  333|      0|        return "==";
  334|      1|      case not_equal:
  ------------------
  |  Branch (334:7): [True: 1, False: 9]
  ------------------
  335|      1|        return "!=";
  336|      3|      case less:
  ------------------
  |  Branch (336:7): [True: 3, False: 7]
  ------------------
  337|      3|        return "<";
  338|      6|      case greater:
  ------------------
  |  Branch (338:7): [True: 6, False: 4]
  ------------------
  339|      6|        return ">";
  340|      0|      case less_equal:
  ------------------
  |  Branch (340:7): [True: 0, False: 10]
  ------------------
  341|      0|        return "<=";
  342|      0|      case greater_equal:
  ------------------
  |  Branch (342:7): [True: 0, False: 10]
  ------------------
  343|      0|        return ">=";
  344|     10|    }
  345|      0|    return "";
  346|     10|  }
_ZZNK2BT3Ast14ExprComparison8evaluateERNS0_11EnvironmentEENKUlRKT_RKT0_NS1_4op_tEE_clIddEEDaS6_S9_SA_:
  353|   233k|    auto SwitchImpl = [&](const auto& lv, const auto& rv, op_t op) {
  354|   233k|      switch(op)
  ------------------
  |  Branch (354:14): [True: 233k, False: 0]
  ------------------
  355|   233k|      {
  356|  2.31k|        case equal:
  ------------------
  |  Branch (356:9): [True: 2.31k, False: 231k]
  ------------------
  357|  2.31k|          if(!IsSame(lv, rv))
  ------------------
  |  Branch (357:14): [True: 602, False: 1.70k]
  ------------------
  358|    602|            return false;
  359|  1.70k|          break;
  360|  16.6k|        case not_equal:
  ------------------
  |  Branch (360:9): [True: 16.6k, False: 217k]
  ------------------
  361|  16.6k|          if(IsSame(lv, rv))
  ------------------
  |  Branch (361:14): [True: 583, False: 16.0k]
  ------------------
  362|    583|            return false;
  363|  16.0k|          break;
  364|   106k|        case less:
  ------------------
  |  Branch (364:9): [True: 106k, False: 127k]
  ------------------
  365|   106k|          if(lv >= rv)
  ------------------
  |  Branch (365:14): [True: 737, False: 105k]
  ------------------
  366|    737|            return false;
  367|   105k|          break;
  368|   106k|        case greater:
  ------------------
  |  Branch (368:9): [True: 106k, False: 127k]
  ------------------
  369|   106k|          if(lv <= rv)
  ------------------
  |  Branch (369:14): [True: 850, False: 105k]
  ------------------
  370|    850|            return false;
  371|   105k|          break;
  372|   105k|        case less_equal:
  ------------------
  |  Branch (372:9): [True: 1.18k, False: 232k]
  ------------------
  373|  1.18k|          if(lv > rv)
  ------------------
  |  Branch (373:14): [True: 590, False: 594]
  ------------------
  374|    590|            return false;
  375|    594|          break;
  376|  1.40k|        case greater_equal:
  ------------------
  |  Branch (376:9): [True: 1.40k, False: 232k]
  ------------------
  377|  1.40k|          if(lv < rv)
  ------------------
  |  Branch (377:14): [True: 597, False: 809]
  ------------------
  378|    597|            return false;
  379|    809|          break;
  380|   233k|      }
  381|   229k|      return true;
  382|   233k|    };
_ZN2BT3Ast6IsSameIdEEbRKT_S4_:
  304|  18.9k|{
  305|       |  if constexpr(std::is_same_v<double, T>)
  306|  18.9k|  {
  307|  18.9k|    constexpr double EPS = static_cast<double>(std::numeric_limits<float>::epsilon());
  308|  18.9k|    return std::abs(lv - rv) <= EPS;
  309|       |  }
  310|       |  else
  311|       |  {
  312|       |    return (lv == rv);
  313|       |  }
  314|  18.9k|}
_ZZNK2BT3Ast14ExprComparison8evaluateERNS0_11EnvironmentEENKUlRKT_RKT0_NS1_4op_tEE_clIN7SafeAny12SimpleStringESE_EEDaS6_S9_SA_:
  353|  8.46k|    auto SwitchImpl = [&](const auto& lv, const auto& rv, op_t op) {
  354|  8.46k|      switch(op)
  ------------------
  |  Branch (354:14): [True: 8.46k, False: 0]
  ------------------
  355|  8.46k|      {
  356|    959|        case equal:
  ------------------
  |  Branch (356:9): [True: 959, False: 7.51k]
  ------------------
  357|    959|          if(!IsSame(lv, rv))
  ------------------
  |  Branch (357:14): [True: 568, False: 391]
  ------------------
  358|    568|            return false;
  359|    391|          break;
  360|  1.11k|        case not_equal:
  ------------------
  |  Branch (360:9): [True: 1.11k, False: 7.35k]
  ------------------
  361|  1.11k|          if(IsSame(lv, rv))
  ------------------
  |  Branch (361:14): [True: 511, False: 601]
  ------------------
  362|    511|            return false;
  363|    601|          break;
  364|  1.48k|        case less:
  ------------------
  |  Branch (364:9): [True: 1.48k, False: 6.98k]
  ------------------
  365|  1.48k|          if(lv >= rv)
  ------------------
  |  Branch (365:14): [True: 937, False: 545]
  ------------------
  366|    937|            return false;
  367|    545|          break;
  368|  1.66k|        case greater:
  ------------------
  |  Branch (368:9): [True: 1.66k, False: 6.80k]
  ------------------
  369|  1.66k|          if(lv <= rv)
  ------------------
  |  Branch (369:14): [True: 794, False: 874]
  ------------------
  370|    794|            return false;
  371|    874|          break;
  372|  1.36k|        case less_equal:
  ------------------
  |  Branch (372:9): [True: 1.36k, False: 7.10k]
  ------------------
  373|  1.36k|          if(lv > rv)
  ------------------
  |  Branch (373:14): [True: 498, False: 867]
  ------------------
  374|    498|            return false;
  375|    867|          break;
  376|  1.88k|        case greater_equal:
  ------------------
  |  Branch (376:9): [True: 1.88k, False: 6.58k]
  ------------------
  377|  1.88k|          if(lv < rv)
  ------------------
  |  Branch (377:14): [True: 811, False: 1.07k]
  ------------------
  378|    811|            return false;
  379|  1.07k|          break;
  380|  8.46k|      }
  381|  4.35k|      return true;
  382|  8.46k|    };
_ZN2BT3Ast6IsSameIN7SafeAny12SimpleStringEEEbRKT_S6_:
  304|  2.07k|{
  305|       |  if constexpr(std::is_same_v<double, T>)
  306|       |  {
  307|       |    constexpr double EPS = static_cast<double>(std::numeric_limits<float>::epsilon());
  308|       |    return std::abs(lv - rv) <= EPS;
  309|       |  }
  310|       |  else
  311|  2.07k|  {
  312|  2.07k|    return (lv == rv);
  313|  2.07k|  }
  314|  2.07k|}
_ZN2BT3Ast20ExprBinaryArithmeticC2ESt10shared_ptrINS0_8ExprBaseEENS1_4op_tES4_:
  199|  35.3k|    : op(op), lhs(std::move(lhs)), rhs(std::move(rhs))
  200|  35.3k|  {}
_ZNK2BT3Ast20ExprBinaryArithmetic8evaluateERNS0_11EnvironmentE:
  203|  13.1k|  {
  204|  13.1k|    auto lhs_v = lhs->evaluate(env);
  205|  13.1k|    auto rhs_v = rhs->evaluate(env);
  206|       |
  207|  13.1k|    if(lhs_v.empty())
  ------------------
  |  Branch (207:8): [True: 11, False: 13.1k]
  ------------------
  208|     11|    {
  209|     11|      throw RuntimeError(ErrorNotInit("left", opStr()));
  210|     11|    }
  211|  13.1k|    if(rhs_v.empty())
  ------------------
  |  Branch (211:8): [True: 2, False: 13.1k]
  ------------------
  212|      2|    {
  213|      2|      throw RuntimeError(ErrorNotInit("right", opStr()));
  214|      2|    }
  215|       |
  216|  13.1k|    if(rhs_v.isNumber() && lhs_v.isNumber())
  ------------------
  |  Branch (216:8): [True: 5.90k, False: 7.23k]
  |  Branch (216:28): [True: 4.12k, False: 1.77k]
  ------------------
  217|  4.12k|    {
  218|  4.12k|      auto lv = lhs_v.cast<double>();
  219|  4.12k|      auto rv = rhs_v.cast<double>();
  220|       |
  221|  4.12k|      switch(op)
  222|  4.12k|      {
  223|    381|        case plus:
  ------------------
  |  Branch (223:9): [True: 381, False: 3.74k]
  ------------------
  224|    381|          return Any(lv + rv);
  225|    531|        case minus:
  ------------------
  |  Branch (225:9): [True: 531, False: 3.59k]
  ------------------
  226|    531|          return Any(lv - rv);
  227|    266|        case times:
  ------------------
  |  Branch (227:9): [True: 266, False: 3.86k]
  ------------------
  228|    266|          return Any(lv * rv);
  229|    278|        case div:
  ------------------
  |  Branch (229:9): [True: 278, False: 3.85k]
  ------------------
  230|    278|          return Any(lv / rv);
  231|  2.67k|        default: {
  ------------------
  |  Branch (231:9): [True: 2.67k, False: 1.45k]
  ------------------
  232|  2.67k|        }
  233|  4.12k|      }
  234|       |
  235|  2.67k|      if(op == bit_and || op == bit_or || op == bit_xor)
  ------------------
  |  Branch (235:10): [True: 344, False: 2.32k]
  |  Branch (235:27): [True: 408, False: 1.91k]
  |  Branch (235:43): [True: 234, False: 1.68k]
  ------------------
  236|    986|      {
  237|    986|        try
  238|    986|        {
  239|    986|          int64_t li = lhs_v.cast<int64_t>();
  240|    986|          int64_t ri = rhs_v.cast<int64_t>();
  241|    986|          switch(op)
  242|    986|          {
  243|    341|            case bit_and:
  ------------------
  |  Branch (243:13): [True: 341, False: 645]
  ------------------
  244|    341|              return Any(static_cast<double>(li & ri));
  245|    405|            case bit_or:
  ------------------
  |  Branch (245:13): [True: 405, False: 581]
  ------------------
  246|    405|              return Any(static_cast<double>(li | ri));
  247|    234|            case bit_xor:
  ------------------
  |  Branch (247:13): [True: 234, False: 752]
  ------------------
  248|    234|              return Any(static_cast<double>(li ^ ri));
  249|      0|            default: {
  ------------------
  |  Branch (249:13): [True: 0, False: 986]
  ------------------
  250|      0|            }
  251|    986|          }
  252|    986|        }
  253|    986|        catch(...)
  254|    986|        {
  255|      6|          throw RuntimeError("Binary operators are not allowed if "
  256|      6|                             "one of the operands is not an integer");
  257|      6|        }
  258|    986|      }
  259|       |
  260|  1.68k|      if(op == logic_or || op == logic_and)
  ------------------
  |  Branch (260:10): [True: 800, False: 884]
  |  Branch (260:28): [True: 650, False: 234]
  ------------------
  261|  1.45k|      {
  262|  1.45k|        try
  263|  1.45k|        {
  264|  1.45k|          auto lb = lhs_v.cast<bool>();
  265|  1.45k|          auto rb = rhs_v.cast<bool>();
  266|  1.45k|          switch(op)
  267|  1.45k|          {
  268|    767|            case logic_or:
  ------------------
  |  Branch (268:13): [True: 767, False: 683]
  ------------------
  269|    767|              return Any(static_cast<double>(lb || rb));
  ------------------
  |  Branch (269:46): [True: 341, False: 426]
  |  Branch (269:52): [True: 3, False: 423]
  ------------------
  270|    558|            case logic_and:
  ------------------
  |  Branch (270:13): [True: 558, False: 892]
  ------------------
  271|    558|              return Any(static_cast<double>(lb && rb));
  ------------------
  |  Branch (271:46): [True: 355, False: 203]
  |  Branch (271:52): [True: 349, False: 6]
  ------------------
  272|      0|            default: {
  ------------------
  |  Branch (272:13): [True: 0, False: 1.45k]
  ------------------
  273|      0|            }
  274|  1.45k|          }
  275|  1.45k|        }
  276|  1.45k|        catch(...)
  277|  1.45k|        {
  278|    125|          throw RuntimeError("Logic operators are not allowed if "
  279|    125|                             "one of the operands is not castable to bool");
  280|    125|        }
  281|  1.45k|      }
  282|  1.68k|    }
  283|  9.01k|    else if(rhs_v.isString() && lhs_v.isString() && op == plus)
  ------------------
  |  Branch (283:13): [True: 6.94k, False: 2.06k]
  |  Branch (283:33): [True: 5.25k, False: 1.69k]
  |  Branch (283:53): [True: 4.85k, False: 395]
  ------------------
  284|  4.85k|    {
  285|  4.85k|      return Any(lhs_v.cast<std::string>() + rhs_v.cast<std::string>());
  286|  4.85k|    }
  287|  4.15k|    else if(op == concat && ((rhs_v.isString() && lhs_v.isString()) ||
  ------------------
  |  Branch (287:13): [True: 3.83k, False: 318]
  |  Branch (287:31): [True: 2.07k, False: 1.76k]
  |  Branch (287:51): [True: 384, False: 1.68k]
  ------------------
  288|  3.45k|                             (rhs_v.isString() && lhs_v.isNumber()) ||
  ------------------
  |  Branch (288:31): [True: 1.68k, False: 1.76k]
  |  Branch (288:51): [True: 1.68k, False: 0]
  ------------------
  289|  1.76k|                             (rhs_v.isNumber() && lhs_v.isString())))
  ------------------
  |  Branch (289:31): [True: 1.76k, False: 0]
  |  Branch (289:51): [True: 1.76k, False: 0]
  ------------------
  290|  3.83k|    {
  291|  3.83k|      return Any(lhs_v.cast<std::string>() + rhs_v.cast<std::string>());
  292|  3.83k|    }
  293|    318|    else
  294|    318|    {
  295|    318|      throw RuntimeError("Operation not permitted");
  296|    318|    }
  297|       |
  298|    234|    return {};  // unreachable
  299|  13.1k|  }
_ZNK2BT3Ast20ExprBinaryArithmetic5opStrEv:
  169|     13|  {
  170|     13|    switch(op)
  ------------------
  |  Branch (170:12): [True: 13, False: 0]
  ------------------
  171|     13|    {
  172|      0|      case plus:
  ------------------
  |  Branch (172:7): [True: 0, False: 13]
  ------------------
  173|      0|        return "+";
  174|      1|      case minus:
  ------------------
  |  Branch (174:7): [True: 1, False: 12]
  ------------------
  175|      1|        return "-";
  176|      3|      case times:
  ------------------
  |  Branch (176:7): [True: 3, False: 10]
  ------------------
  177|      3|        return "*";
  178|      3|      case div:
  ------------------
  |  Branch (178:7): [True: 3, False: 10]
  ------------------
  179|      3|        return "/";
  180|      0|      case concat:
  ------------------
  |  Branch (180:7): [True: 0, False: 13]
  ------------------
  181|      0|        return "..";
  182|      3|      case bit_and:
  ------------------
  |  Branch (182:7): [True: 3, False: 10]
  ------------------
  183|      3|        return "&";
  184|      1|      case bit_or:
  ------------------
  |  Branch (184:7): [True: 1, False: 12]
  ------------------
  185|      1|        return "|";
  186|      1|      case bit_xor:
  ------------------
  |  Branch (186:7): [True: 1, False: 12]
  ------------------
  187|      1|        return "^";
  188|      0|      case logic_and:
  ------------------
  |  Branch (188:7): [True: 0, False: 13]
  ------------------
  189|      0|        return "&&";
  190|      1|      case logic_or:
  ------------------
  |  Branch (190:7): [True: 1, False: 12]
  ------------------
  191|      1|        return "||";
  192|     13|    }
  193|      0|    return "";
  194|     13|  }

_ZN7SafeAny7details13convertNumberIldEEvRKT_RT0_:
  152|   267k|{
  153|   267k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  154|   267k|                                                                          "convertible");
  155|       |
  156|   267k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (156:34): [True: 0, Folded]
  |  Branch (156:55): [Folded, False: 0]
  ------------------
  157|       |
  158|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  159|       |  {
  160|       |    if(source < 0)
  161|       |    {
  162|       |      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  163|       |    }
  164|       |  }
  165|       |  // these conversions are always safe (no check needed):
  166|       |  // - same type
  167|       |  // - float -> double
  168|       |  // - floating point to bool (C-style: any non-zero is true)
  169|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  170|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  171|       |  {
  172|       |    target = static_cast<DST>(source);
  173|       |  }
  174|       |  // integer to bool: only 0 and 1 are valid
  175|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  176|       |  {
  177|       |    checkLowerLimit<SRC, DST>(source);
  178|       |    target = static_cast<DST>(source);
  179|       |  }
  180|       |  else if constexpr(both_integers)
  181|       |  {
  182|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  183|       |    {
  184|       |      checkUpperLimit<SRC, DST>(source);
  185|       |    }
  186|       |    // casting to a smaller number need to be check
  187|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  188|       |    {
  189|       |      if constexpr(is_signed<SRC>())
  190|       |      {
  191|       |        checkLowerLimit<SRC, DST>(source);
  192|       |      }
  193|       |      checkUpperLimit<SRC, DST>(source);
  194|       |    }
  195|       |    target = static_cast<DST>(source);
  196|       |  }
  197|       |  // casting to/from floating points might cause truncation.
  198|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  199|       |                    std::is_floating_point<DST>::value)
  200|   267k|  {
  201|   267k|    bool both_float =
  202|   267k|        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  ------------------
  |  Branch (202:9): [Folded, False: 267k]
  |  Branch (202:47): [True: 0, Folded]
  ------------------
  203|       |    // to avoid being too pedantic, let's accept casting between double and float
  204|   267k|    if(!both_float)
  ------------------
  |  Branch (204:8): [True: 267k, False: 0]
  ------------------
  205|   267k|    {
  206|   267k|      checkTruncation<SRC, DST>(source);
  207|   267k|    }
  208|   267k|    target = static_cast<DST>(source);
  209|   267k|  }
  210|   267k|}
_ZN7SafeAny7details15checkTruncationIldEEvRKT_:
   92|   267k|{
   93|       |  // Handle integer to floating point
   94|       |  if constexpr(std::is_integral_v<From> && std::is_floating_point_v<To>)
   95|   267k|  {
   96|       |    // Check if value can be represented exactly in the target type
   97|   267k|    constexpr uint64_t max_exact = (1LL << std::numeric_limits<double>::digits) - 1;
   98|   267k|    bool doesnt_fit = false;
   99|       |    if constexpr(!std::is_signed_v<From>)
  100|       |    {
  101|       |      doesnt_fit = static_cast<uint64_t>(from) > max_exact;
  102|       |    }
  103|       |    else
  104|   267k|    {
  105|   267k|      doesnt_fit = std::abs(static_cast<int64_t>(from)) > static_cast<int64_t>(max_exact);
  106|   267k|    }
  107|   267k|    if(doesnt_fit)
  ------------------
  |  Branch (107:8): [True: 20, False: 267k]
  ------------------
  108|     20|    {
  109|     20|      throw std::runtime_error("Loss of precision when converting a large integer number "
  110|     20|                               "to floating point:" +
  111|     20|                               std::to_string(from));
  112|     20|    }
  113|       |  }
  114|       |  // Handle floating point to integer
  115|       |  else if constexpr(std::is_floating_point_v<From> && std::is_integral_v<To>)
  116|       |  {
  117|       |    // static_cast<From>(To::max) rounds up to an out-of-range value when To has
  118|       |    // more significant bits than From's mantissa (e.g. double -> int64_t). In
  119|       |    // that case a plain `>` lets the rounded boundary through and the cast to To
  120|       |    // below overflows, so use a half-open upper bound to reject it first.
  121|       |    constexpr bool max_rounds_up =
  122|       |        std::numeric_limits<To>::digits > std::numeric_limits<From>::digits;
  123|       |    const From max_limit = static_cast<From>(std::numeric_limits<To>::max());
  124|       |    const bool over = max_rounds_up ? (from >= max_limit) : (from > max_limit);
  125|       |    if(over || from < static_cast<From>(std::numeric_limits<To>::lowest()) ||
  126|       |       from != std::nearbyint(from))
  127|       |    {
  128|       |      throw std::runtime_error("Invalid floating point to integer conversion");
  129|       |    }
  130|       |  }
  131|       |  // Handle other conversions
  132|       |  else
  133|       |  {
  134|       |    if(from > static_cast<From>(std::numeric_limits<To>::max()) ||
  135|       |       from < static_cast<From>(std::numeric_limits<To>::lowest()))
  136|       |    {
  137|       |      throw std::runtime_error("Value outside numeric limits");
  138|       |    }
  139|       |    To as_target = static_cast<To>(from);
  140|       |    From back_to_source = static_cast<From>(as_target);
  141|       |    if(from != back_to_source)
  142|       |    {
  143|       |      throw std::runtime_error("Value truncated in conversion");
  144|       |    }
  145|       |  }
  146|   267k|}
_ZN7SafeAny7details13convertNumberIdlEEvRKT_RT0_:
  152|  1.94k|{
  153|  1.94k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  154|  1.94k|                                                                          "convertible");
  155|       |
  156|  1.94k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (156:34): [Folded, False: 1.94k]
  |  Branch (156:55): [True: 0, Folded]
  ------------------
  157|       |
  158|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  159|       |  {
  160|       |    if(source < 0)
  161|       |    {
  162|       |      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  163|       |    }
  164|       |  }
  165|       |  // these conversions are always safe (no check needed):
  166|       |  // - same type
  167|       |  // - float -> double
  168|       |  // - floating point to bool (C-style: any non-zero is true)
  169|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  170|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  171|       |  {
  172|       |    target = static_cast<DST>(source);
  173|       |  }
  174|       |  // integer to bool: only 0 and 1 are valid
  175|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  176|       |  {
  177|       |    checkLowerLimit<SRC, DST>(source);
  178|       |    target = static_cast<DST>(source);
  179|       |  }
  180|       |  else if constexpr(both_integers)
  181|       |  {
  182|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  183|       |    {
  184|       |      checkUpperLimit<SRC, DST>(source);
  185|       |    }
  186|       |    // casting to a smaller number need to be check
  187|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  188|       |    {
  189|       |      if constexpr(is_signed<SRC>())
  190|       |      {
  191|       |        checkLowerLimit<SRC, DST>(source);
  192|       |      }
  193|       |      checkUpperLimit<SRC, DST>(source);
  194|       |    }
  195|       |    target = static_cast<DST>(source);
  196|       |  }
  197|       |  // casting to/from floating points might cause truncation.
  198|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  199|       |                    std::is_floating_point<DST>::value)
  200|  1.94k|  {
  201|  1.94k|    bool both_float =
  202|  1.94k|        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  ------------------
  |  Branch (202:9): [True: 1.94k, Folded]
  |  Branch (202:47): [Folded, False: 1.94k]
  ------------------
  203|       |    // to avoid being too pedantic, let's accept casting between double and float
  204|  1.94k|    if(!both_float)
  ------------------
  |  Branch (204:8): [True: 1.94k, False: 0]
  ------------------
  205|  1.94k|    {
  206|  1.94k|      checkTruncation<SRC, DST>(source);
  207|  1.94k|    }
  208|  1.94k|    target = static_cast<DST>(source);
  209|  1.94k|  }
  210|  1.94k|}
_ZN7SafeAny7details15checkTruncationIdlEEvRKT_:
   92|  1.94k|{
   93|       |  // Handle integer to floating point
   94|       |  if constexpr(std::is_integral_v<From> && std::is_floating_point_v<To>)
   95|       |  {
   96|       |    // Check if value can be represented exactly in the target type
   97|       |    constexpr uint64_t max_exact = (1LL << std::numeric_limits<double>::digits) - 1;
   98|       |    bool doesnt_fit = false;
   99|       |    if constexpr(!std::is_signed_v<From>)
  100|       |    {
  101|       |      doesnt_fit = static_cast<uint64_t>(from) > max_exact;
  102|       |    }
  103|       |    else
  104|       |    {
  105|       |      doesnt_fit = std::abs(static_cast<int64_t>(from)) > static_cast<int64_t>(max_exact);
  106|       |    }
  107|       |    if(doesnt_fit)
  108|       |    {
  109|       |      throw std::runtime_error("Loss of precision when converting a large integer number "
  110|       |                               "to floating point:" +
  111|       |                               std::to_string(from));
  112|       |    }
  113|       |  }
  114|       |  // Handle floating point to integer
  115|       |  else if constexpr(std::is_floating_point_v<From> && std::is_integral_v<To>)
  116|  1.94k|  {
  117|       |    // static_cast<From>(To::max) rounds up to an out-of-range value when To has
  118|       |    // more significant bits than From's mantissa (e.g. double -> int64_t). In
  119|       |    // that case a plain `>` lets the rounded boundary through and the cast to To
  120|       |    // below overflows, so use a half-open upper bound to reject it first.
  121|  1.94k|    constexpr bool max_rounds_up =
  122|  1.94k|        std::numeric_limits<To>::digits > std::numeric_limits<From>::digits;
  123|  1.94k|    const From max_limit = static_cast<From>(std::numeric_limits<To>::max());
  124|  1.94k|    const bool over = max_rounds_up ? (from >= max_limit) : (from > max_limit);
  ------------------
  |  Branch (124:23): [True: 1.94k, Folded]
  ------------------
  125|  1.94k|    if(over || from < static_cast<From>(std::numeric_limits<To>::lowest()) ||
  ------------------
  |  Branch (125:8): [True: 2, False: 1.94k]
  |  Branch (125:16): [True: 2, False: 1.94k]
  ------------------
  126|  1.94k|       from != std::nearbyint(from))
  ------------------
  |  Branch (126:8): [True: 8, False: 1.93k]
  ------------------
  127|     12|    {
  128|     12|      throw std::runtime_error("Invalid floating point to integer conversion");
  129|     12|    }
  130|       |  }
  131|       |  // Handle other conversions
  132|       |  else
  133|       |  {
  134|       |    if(from > static_cast<From>(std::numeric_limits<To>::max()) ||
  135|       |       from < static_cast<From>(std::numeric_limits<To>::lowest()))
  136|       |    {
  137|       |      throw std::runtime_error("Value outside numeric limits");
  138|       |    }
  139|       |    To as_target = static_cast<To>(from);
  140|       |    From back_to_source = static_cast<From>(as_target);
  141|       |    if(from != back_to_source)
  142|       |    {
  143|       |      throw std::runtime_error("Value truncated in conversion");
  144|       |    }
  145|       |  }
  146|  1.94k|}
_ZN7SafeAny7details13convertNumberIlbEEvRKT_RT0_:
  152|  1.65k|{
  153|  1.65k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  154|  1.65k|                                                                          "convertible");
  155|       |
  156|  1.65k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (156:34): [True: 0, Folded]
  |  Branch (156:55): [True: 0, Folded]
  ------------------
  157|       |
  158|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  159|  1.65k|  {
  160|  1.65k|    if(source < 0)
  ------------------
  |  Branch (160:8): [True: 53, False: 1.60k]
  ------------------
  161|     53|    {
  162|     53|      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  163|     53|    }
  164|  1.65k|  }
  165|       |  // these conversions are always safe (no check needed):
  166|       |  // - same type
  167|       |  // - float -> double
  168|       |  // - floating point to bool (C-style: any non-zero is true)
  169|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  170|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  171|       |  {
  172|       |    target = static_cast<DST>(source);
  173|       |  }
  174|       |  // integer to bool: only 0 and 1 are valid
  175|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  176|  1.65k|  {
  177|  1.65k|    checkLowerLimit<SRC, DST>(source);
  178|  1.65k|    target = static_cast<DST>(source);
  179|       |  }
  180|       |  else if constexpr(both_integers)
  181|       |  {
  182|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  183|       |    {
  184|       |      checkUpperLimit<SRC, DST>(source);
  185|       |    }
  186|       |    // casting to a smaller number need to be check
  187|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  188|       |    {
  189|       |      if constexpr(is_signed<SRC>())
  190|       |      {
  191|       |        checkLowerLimit<SRC, DST>(source);
  192|       |      }
  193|       |      checkUpperLimit<SRC, DST>(source);
  194|       |    }
  195|       |    target = static_cast<DST>(source);
  196|       |  }
  197|       |  // casting to/from floating points might cause truncation.
  198|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  199|       |                    std::is_floating_point<DST>::value)
  200|       |  {
  201|       |    bool both_float =
  202|       |        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  203|       |    // to avoid being too pedantic, let's accept casting between double and float
  204|       |    if(!both_float)
  205|       |    {
  206|       |      checkTruncation<SRC, DST>(source);
  207|       |    }
  208|       |    target = static_cast<DST>(source);
  209|       |  }
  210|  1.65k|}
_ZN7SafeAny7details15checkLowerLimitIlbEEvRKT_:
   76|  1.60k|{
   77|       |  if constexpr(std::is_same<To, bool>::value)
   78|  1.60k|  {
   79|  1.60k|    if(from != 0 && from != 1)
  ------------------
  |  Branch (79:8): [True: 731, False: 874]
  |  Branch (79:21): [True: 71, False: 660]
  ------------------
   80|     71|    {
   81|     71|      throw std::runtime_error("Implicit casting to bool is not allowed");
   82|     71|    }
   83|       |  }
   84|       |  else if(from < std::numeric_limits<To>::min())
   85|       |  {
   86|       |    throw std::runtime_error("Value outside the lovest numerical limit.");
   87|       |  }
   88|  1.60k|}
_ZN7SafeAny7details13convertNumberIdbEEvRKT_RT0_:
  152|  1.14k|{
  153|  1.14k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  154|  1.14k|                                                                          "convertible");
  155|       |
  156|  1.14k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (156:34): [Folded, False: 1.14k]
  |  Branch (156:55): [True: 0, Folded]
  ------------------
  157|       |
  158|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  159|  1.14k|  {
  160|  1.14k|    if(source < 0)
  ------------------
  |  Branch (160:8): [True: 1, False: 1.14k]
  ------------------
  161|      1|    {
  162|      1|      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  163|      1|    }
  164|  1.14k|  }
  165|       |  // these conversions are always safe (no check needed):
  166|       |  // - same type
  167|       |  // - float -> double
  168|       |  // - floating point to bool (C-style: any non-zero is true)
  169|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  170|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  171|  1.14k|  {
  172|  1.14k|    target = static_cast<DST>(source);
  173|       |  }
  174|       |  // integer to bool: only 0 and 1 are valid
  175|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  176|       |  {
  177|       |    checkLowerLimit<SRC, DST>(source);
  178|       |    target = static_cast<DST>(source);
  179|       |  }
  180|       |  else if constexpr(both_integers)
  181|       |  {
  182|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  183|       |    {
  184|       |      checkUpperLimit<SRC, DST>(source);
  185|       |    }
  186|       |    // casting to a smaller number need to be check
  187|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  188|       |    {
  189|       |      if constexpr(is_signed<SRC>())
  190|       |      {
  191|       |        checkLowerLimit<SRC, DST>(source);
  192|       |      }
  193|       |      checkUpperLimit<SRC, DST>(source);
  194|       |    }
  195|       |    target = static_cast<DST>(source);
  196|       |  }
  197|       |  // casting to/from floating points might cause truncation.
  198|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  199|       |                    std::is_floating_point<DST>::value)
  200|       |  {
  201|       |    bool both_float =
  202|       |        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  203|       |    // to avoid being too pedantic, let's accept casting between double and float
  204|       |    if(!both_float)
  205|       |    {
  206|       |      checkTruncation<SRC, DST>(source);
  207|       |    }
  208|       |    target = static_cast<DST>(source);
  209|       |  }
  210|  1.14k|}

_ZN2BT8demangleB5cxx11ERKSt10type_index:
   86|  16.4k|{
   87|  16.4k|  if(index == typeid(std::string))
  ------------------
  |  Branch (87:6): [True: 100, False: 16.3k]
  ------------------
   88|    100|  {
   89|    100|    return "std::string";
   90|    100|  }
   91|  16.3k|  if(index == typeid(std::string_view))
  ------------------
  |  Branch (91:6): [True: 0, False: 16.3k]
  ------------------
   92|      0|  {
   93|      0|    return "std::string_view";
   94|      0|  }
   95|  16.3k|  if(index == typeid(std::chrono::seconds))
  ------------------
  |  Branch (95:6): [True: 0, False: 16.3k]
  ------------------
   96|      0|  {
   97|      0|    return "std::chrono::seconds";
   98|      0|  }
   99|  16.3k|  if(index == typeid(std::chrono::milliseconds))
  ------------------
  |  Branch (99:6): [True: 0, False: 16.3k]
  ------------------
  100|      0|  {
  101|      0|    return "std::chrono::milliseconds";
  102|      0|  }
  103|  16.3k|  if(index == typeid(std::chrono::microseconds))
  ------------------
  |  Branch (103:6): [True: 0, False: 16.3k]
  ------------------
  104|      0|  {
  105|      0|    return "std::chrono::microseconds";
  106|      0|  }
  107|       |
  108|  16.3k|  scoped_demangled_name demangled_name(index.name());
  109|  16.3k|  char const* const p = demangled_name.get();
  110|  16.3k|  if(p != nullptr)
  ------------------
  |  Branch (110:6): [True: 16.3k, False: 0]
  ------------------
  111|  16.3k|  {
  112|  16.3k|    return p;
  113|  16.3k|  }
  114|      0|  return index.name();
  115|  16.3k|}
_ZN2BT21scoped_demangled_nameC2EPKc:
   34|  16.3k|  explicit scoped_demangled_name(char const* name) noexcept : m_p(demangle_alloc(name))
   35|  16.3k|  {}
_ZN2BT14demangle_allocEPKc:
   56|  16.3k|{
   57|  16.3k|  int status = 0;
   58|  16.3k|  std::size_t size = 0;
   59|       |  return abi::__cxa_demangle(name, NULL, &size, &status);
   60|  16.3k|}
_ZNK2BT21scoped_demangled_name3getEv:
   43|  16.3k|  {
   44|  16.3k|    return m_p;
   45|  16.3k|  }
_ZN2BT21scoped_demangled_nameD2Ev:
   38|  16.3k|  {
   39|  16.3k|    demangle_free(m_p);
   40|  16.3k|  }
_ZN2BT13demangle_freeEPKc:
   63|  16.3k|{
   64|       |  // NOLINTNEXTLINE(cppcoreguidelines-no-malloc,cppcoreguidelines-owning-memory)
   65|  16.3k|  std::free(const_cast<char*>(name));
   66|  16.3k|}

_ZNK2BT9LockedPtrINS_3AnyEEcvbEv:
   52|   112k|  {
   53|   112k|    return ref_ != nullptr;
   54|   112k|  }
_ZNK2BT9LockedPtrINS_3AnyEE3getEv:
   73|   111k|  {
   74|   111k|    return ref_;
   75|   111k|  }
_ZN2BT9LockedPtrINS_3AnyEED2Ev:
   28|   112k|  {
   29|   112k|    if(mutex_ != nullptr)
  ------------------
  |  Branch (29:8): [True: 111k, False: 524]
  ------------------
   30|   111k|    {
   31|   111k|      mutex_->unlock();
   32|   111k|    }
   33|   112k|  }
_ZN2BT9LockedPtrINS_3AnyEEC2Ev:
   20|    524|  LockedPtr() = default;
_ZN2BT9LockedPtrINS_3AnyEEC2EPS1_PSt5mutex:
   22|   111k|  LockedPtr(T* obj, std::mutex* obj_mutex) : ref_(obj), mutex_(obj_mutex)
   23|   111k|  {
   24|   111k|    mutex_->lock();
   25|   111k|  }

_ZNK2BT3Any8isNumberEv:
  354|   617k|{
  355|   617k|  return _any.type() == typeid(int64_t) || _any.type() == typeid(uint64_t) ||
  ------------------
  |  Branch (355:10): [True: 372k, False: 244k]
  |  Branch (355:44): [True: 0, False: 244k]
  ------------------
  356|   244k|         _any.type() == typeid(double);
  ------------------
  |  Branch (356:10): [True: 14.4k, False: 229k]
  ------------------
  357|   617k|}
_ZN2BT3AnyC2Ev:
   78|  62.6k|  Any() : _original_type(UndefinedAnyType)
   79|  62.6k|  {}
_ZN2BT3AnyD2Ev:
   81|  6.13M|  ~Any() = default;
_ZNK2BT3Any4castIdEET_v:
  169|   484k|  {
  170|   484k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 483k, False: 188]
  ------------------
  171|   483k|    {
  172|   483k|      return res.value();
  173|   483k|    }
  174|    188|    else
  175|    188|    {
  176|    188|      throw std::runtime_error(res.error());
  177|    188|    }
  178|   484k|  }
_ZNK2BT3Any7tryCastIdEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  522|   484k|{
  523|   484k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  524|   484k|                                              "can not cast to reference");
  525|       |
  526|   484k|  if(_any.empty())
  ------------------
  |  Branch (526:6): [True: 2, False: 484k]
  ------------------
  527|      2|  {
  528|      2|    throw std::runtime_error("Any::cast failed because it is empty");
  529|      2|  }
  530|       |
  531|   484k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (531:6): [True: 8.99k, False: 475k]
  ------------------
  532|  8.99k|  {
  533|  8.99k|    return linb::any_cast<T>(_any);
  534|  8.99k|  }
  535|       |
  536|       |  // special case when the output is an enum.
  537|       |  // We will try first a int conversion
  538|       |  if constexpr(std::is_enum_v<T>)
  539|       |  {
  540|       |    if(isNumber())
  541|       |    {
  542|       |      return static_cast<T>(convert<int>().value());
  543|       |    }
  544|       |    if(isString())
  545|       |    {
  546|       |      if(auto out = stringToNumber<int64_t>())
  547|       |      {
  548|       |        return static_cast<T>(out.value());
  549|       |      }
  550|       |    }
  551|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  552|       |  }
  553|       |
  554|   475k|  if(isString())
  ------------------
  |  Branch (554:6): [True: 207k, False: 267k]
  ------------------
  555|   207k|  {
  556|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  557|   207k|    {
  558|   207k|      if(auto out = stringToNumber<T>())
  ------------------
  |  Branch (558:15): [True: 207k, False: 166]
  ------------------
  559|   207k|      {
  560|   207k|        return out.value();
  561|   207k|      }
  562|    166|      else
  563|    166|      {
  564|    166|        return out;
  565|    166|      }
  566|   207k|    }
  567|   207k|  }
  568|       |
  569|   475k|  if(auto res = convert<T>())
  ------------------
  |  Branch (569:11): [True: 267k, False: 207k]
  ------------------
  570|   267k|  {
  571|   267k|    return std::move(res.value());
  572|   267k|  }
  573|   207k|  else
  574|   207k|  {
  575|   207k|    return res;
  576|   207k|  }
  577|   475k|}
_ZNK2BT3Any10castedTypeEv:
  200|   762k|  {
  201|   762k|    return _any.type();
  202|   762k|  }
_ZNK2BT3Any8isStringEv:
  141|  1.39M|  {
  142|  1.39M|    return _any.type() == typeid(SafeAny::SimpleString);
  143|  1.39M|  }
_ZNK2BT3Any14stringToNumberIdEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  430|   207k|{
  431|   207k|  static_assert(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, "Expecting a "
  432|   207k|                                                                     "numeric type");
  433|       |
  434|   207k|  const auto str = linb::any_cast<SafeAny::SimpleString>(_any);
  435|       |#if __cpp_lib_to_chars >= 201611L
  436|       |  T out;
  437|       |  auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out);
  438|       |  if(err == std::errc())
  439|       |  {
  440|       |    return out;
  441|       |  }
  442|       |  else
  443|       |  {
  444|       |    return nonstd::make_unexpected("Any failed string to number conversion");
  445|       |  }
  446|       |#else
  447|   207k|  try
  448|   207k|  {
  449|       |    if constexpr(std::is_same_v<T, uint16_t>)
  450|       |    {
  451|       |      return std::stoul(str.toStdString());
  452|       |    }
  453|       |    if constexpr(std::is_integral_v<T>)
  454|       |    {
  455|       |      const int64_t val = std::stol(str.toStdString());
  456|       |      Any temp_any(val);
  457|       |      return temp_any.convert<T>();
  458|       |    }
  459|       |    if constexpr(std::is_floating_point_v<T>)
  460|   207k|    {
  461|   207k|      return std::stod(str.toStdString());
  462|   207k|    }
  463|   207k|  }
  464|   207k|  catch(...)
  465|   207k|  {
  466|    166|    return nonstd::make_unexpected("Any failed string to number conversion");
  467|    166|  }
  468|      0|#endif
  469|      0|  return nonstd::make_unexpected("Any conversion from string failed");
  470|   207k|}
_ZNK2BT3Any7convertIdEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEPNSt9enable_ifIXsr3std13is_arithmeticIS5_EE5valueEvE4typeE:
  495|   267k|{
  496|   267k|  using SafeAny::details::convertNumber;
  497|   267k|  DST out;
  498|       |
  499|   267k|  const auto& type = _any.type();
  500|       |
  501|   267k|  if(type == typeid(int64_t))
  ------------------
  |  Branch (501:6): [True: 267k, False: 0]
  ------------------
  502|   267k|  {
  503|   267k|    convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
  504|   267k|  }
  505|      0|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (505:11): [True: 0, False: 0]
  ------------------
  506|      0|  {
  507|      0|    convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
  508|      0|  }
  509|      0|  else if(type == typeid(double))
  ------------------
  |  Branch (509:11): [True: 0, False: 0]
  ------------------
  510|      0|  {
  511|      0|    convertNumber<double, DST>(linb::any_cast<double>(_any), out);
  512|      0|  }
  513|      0|  else
  514|      0|  {
  515|      0|    return nonstd::make_unexpected(errorMsg<DST>());
  516|      0|  }
  517|   267k|  return out;
  518|   267k|}
_ZNK2BT3Any4typeEv:
  194|  16.4k|  {
  195|  16.4k|    return _original_type;
  196|  16.4k|  }
_ZN2BT3AnyC2IiEERKT_PNSt9enable_ifIXoosr3std11is_integralIS2_EE5valuesr3std7is_enumIS2_EE5valueEvE4typeE:
  118|  5.44k|    : _any(int64_t(value)), _original_type(typeid(T))
  119|  5.44k|  {}
_ZN2BT3AnyaSERKS0_:
  337|   264k|{
  338|   264k|  if(this != &other)
  ------------------
  |  Branch (338:6): [True: 264k, False: 0]
  ------------------
  339|   264k|  {
  340|   264k|    this->_any = other._any;
  341|   264k|    this->_original_type = other._original_type;
  342|   264k|  }
  343|   264k|  return *this;
  344|   264k|}
_ZN2BT3AnyaSEOS0_:
  347|  39.3k|{
  348|  39.3k|  this->_any = std::move(other._any);
  349|  39.3k|  this->_original_type = other._original_type;
  350|  39.3k|  return *this;
  351|  39.3k|}
_ZNK2BT3Any8copyIntoERS0_:
  365|  9.24k|{
  366|  9.24k|  if(dst.empty())
  ------------------
  |  Branch (366:6): [True: 0, False: 9.24k]
  ------------------
  367|      0|  {
  368|      0|    dst = *this;
  369|      0|    return;
  370|      0|  }
  371|       |
  372|  9.24k|  const auto& dst_type = dst.castedType();
  373|       |
  374|  9.24k|  if((castedType() == dst_type) || (isString() && dst.isString()))
  ------------------
  |  Branch (374:6): [True: 8.12k, False: 1.12k]
  |  Branch (374:37): [True: 5, False: 1.11k]
  |  Branch (374:51): [True: 0, False: 5]
  ------------------
  375|  8.12k|  {
  376|  8.12k|    dst._any = _any;
  377|  8.12k|  }
  378|  1.12k|  else if(isNumber() && dst.isNumber())
  ------------------
  |  Branch (378:11): [True: 1.11k, False: 5]
  |  Branch (378:25): [True: 1.06k, False: 50]
  ------------------
  379|  1.06k|  {
  380|  1.06k|    if(dst_type == typeid(int64_t))
  ------------------
  |  Branch (380:8): [True: 870, False: 195]
  ------------------
  381|    870|    {
  382|    870|      dst._any = cast<int64_t>();
  383|    870|    }
  384|    195|    else if(dst_type == typeid(uint64_t))
  ------------------
  |  Branch (384:13): [True: 0, False: 195]
  ------------------
  385|      0|    {
  386|      0|      dst._any = cast<uint64_t>();
  387|      0|    }
  388|    195|    else if(dst_type == typeid(double))
  ------------------
  |  Branch (388:13): [True: 195, False: 0]
  ------------------
  389|    195|    {
  390|    195|      dst._any = cast<double>();
  391|    195|    }
  392|      0|    else
  393|      0|    {
  394|      0|      throw std::runtime_error("Any::copyInto fails");
  395|      0|    }
  396|  1.06k|  }
  397|     55|  else
  398|     55|  {
  399|     55|    throw std::runtime_error("Any::copyInto fails");
  400|     55|  }
  401|  9.24k|}
_ZNK2BT3Any5emptyEv:
  205|   556k|  {
  206|   556k|    return _any.empty();
  207|   556k|  }
_ZNK2BT3Any4castIlEET_v:
  169|  2.83k|  {
  170|  2.83k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 2.82k, False: 12]
  ------------------
  171|  2.82k|    {
  172|  2.82k|      return res.value();
  173|  2.82k|    }
  174|     12|    else
  175|     12|    {
  176|     12|      throw std::runtime_error(res.error());
  177|     12|    }
  178|  2.83k|  }
_ZNK2BT3Any7tryCastIlEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  522|  2.83k|{
  523|  2.83k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  524|  2.83k|                                              "can not cast to reference");
  525|       |
  526|  2.83k|  if(_any.empty())
  ------------------
  |  Branch (526:6): [True: 0, False: 2.83k]
  ------------------
  527|      0|  {
  528|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  529|      0|  }
  530|       |
  531|  2.83k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (531:6): [True: 895, False: 1.94k]
  ------------------
  532|    895|  {
  533|    895|    return linb::any_cast<T>(_any);
  534|    895|  }
  535|       |
  536|       |  // special case when the output is an enum.
  537|       |  // We will try first a int conversion
  538|       |  if constexpr(std::is_enum_v<T>)
  539|       |  {
  540|       |    if(isNumber())
  541|       |    {
  542|       |      return static_cast<T>(convert<int>().value());
  543|       |    }
  544|       |    if(isString())
  545|       |    {
  546|       |      if(auto out = stringToNumber<int64_t>())
  547|       |      {
  548|       |        return static_cast<T>(out.value());
  549|       |      }
  550|       |    }
  551|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  552|       |  }
  553|       |
  554|  1.94k|  if(isString())
  ------------------
  |  Branch (554:6): [True: 0, False: 1.94k]
  ------------------
  555|      0|  {
  556|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  557|      0|    {
  558|      0|      if(auto out = stringToNumber<T>())
  ------------------
  |  Branch (558:15): [True: 0, False: 0]
  ------------------
  559|      0|      {
  560|      0|        return out.value();
  561|      0|      }
  562|      0|      else
  563|      0|      {
  564|      0|        return out;
  565|      0|      }
  566|      0|    }
  567|      0|  }
  568|       |
  569|  1.94k|  if(auto res = convert<T>())
  ------------------
  |  Branch (569:11): [True: 1.93k, False: 12]
  ------------------
  570|  1.93k|  {
  571|  1.93k|    return std::move(res.value());
  572|  1.93k|  }
  573|     12|  else
  574|     12|  {
  575|     12|    return res;
  576|     12|  }
  577|  1.94k|}
_ZN2BT3AnyC2IlEERKT_PNSt9enable_ifIXoosr3std11is_integralIS2_EE5valuesr3std7is_enumIS2_EE5valueEvE4typeE:
  118|  1.41M|    : _any(int64_t(value)), _original_type(typeid(T))
  119|  1.41M|  {}
_ZNK2BT3Any7convertIlEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEPNSt9enable_ifIXsr3std13is_arithmeticIS5_EE5valueEvE4typeE:
  495|  1.94k|{
  496|  1.94k|  using SafeAny::details::convertNumber;
  497|  1.94k|  DST out;
  498|       |
  499|  1.94k|  const auto& type = _any.type();
  500|       |
  501|  1.94k|  if(type == typeid(int64_t))
  ------------------
  |  Branch (501:6): [True: 0, False: 1.94k]
  ------------------
  502|      0|  {
  503|      0|    convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
  504|      0|  }
  505|  1.94k|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (505:11): [True: 0, False: 1.94k]
  ------------------
  506|      0|  {
  507|      0|    convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
  508|      0|  }
  509|  1.94k|  else if(type == typeid(double))
  ------------------
  |  Branch (509:11): [True: 1.94k, False: 0]
  ------------------
  510|  1.94k|  {
  511|  1.94k|    convertNumber<double, DST>(linb::any_cast<double>(_any), out);
  512|  1.94k|  }
  513|      0|  else
  514|      0|  {
  515|      0|    return nonstd::make_unexpected(errorMsg<DST>());
  516|      0|  }
  517|  1.94k|  return out;
  518|  1.94k|}
_ZN2BT3AnyC2ERKd:
   90|   268k|  explicit Any(const double& value) : _any(value), _original_type(typeid(double))
   91|   268k|  {}
_ZN2BT3AnyC2IbEERKT_PNSt9enable_ifIXoosr3std11is_integralIS2_EE5valuesr3std7is_enumIS2_EE5valueEvE4typeE:
  118|  5.44k|    : _any(int64_t(value)), _original_type(typeid(T))
  119|  5.44k|  {}
_ZN2BT3AnyC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  100|   380k|    : _any(SafeAny::SimpleString(str)), _original_type(typeid(std::string))
  101|   380k|  {}
_ZN2BT3AnyC2ERKS0_:
   83|  2.18M|  Any(const Any& other) : _any(other._any), _original_type(other._original_type)
   84|  2.18M|  {}
_ZN2BT3AnyC2EOS0_:
   87|  1.78M|    : _any(std::move(other._any)), _original_type(other._original_type)
   88|  1.78M|  {}
_ZN2BT3AnyC2ERKSt10type_index:
  121|  31.2k|  Any(const std::type_index& type) : _original_type(type)
  122|  31.2k|  {}
_ZNK2BT3Any4castINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_v:
  169|   237k|  {
  170|   237k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 237k, False: 0]
  ------------------
  171|   237k|    {
  172|   237k|      return res.value();
  173|   237k|    }
  174|      0|    else
  175|      0|    {
  176|      0|      throw std::runtime_error(res.error());
  177|      0|    }
  178|   237k|  }
_ZNK2BT3Any7tryCastINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEN6nonstd13expected_lite8expectedIT_S7_EEv:
  522|   237k|{
  523|   237k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  524|   237k|                                              "can not cast to reference");
  525|       |
  526|   237k|  if(_any.empty())
  ------------------
  |  Branch (526:6): [True: 0, False: 237k]
  ------------------
  527|      0|  {
  528|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  529|      0|  }
  530|       |
  531|   237k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (531:6): [True: 0, False: 237k]
  ------------------
  532|      0|  {
  533|      0|    return linb::any_cast<T>(_any);
  534|      0|  }
  535|       |
  536|       |  // special case when the output is an enum.
  537|       |  // We will try first a int conversion
  538|       |  if constexpr(std::is_enum_v<T>)
  539|       |  {
  540|       |    if(isNumber())
  541|       |    {
  542|       |      return static_cast<T>(convert<int>().value());
  543|       |    }
  544|       |    if(isString())
  545|       |    {
  546|       |      if(auto out = stringToNumber<int64_t>())
  547|       |      {
  548|       |        return static_cast<T>(out.value());
  549|       |      }
  550|       |    }
  551|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  552|       |  }
  553|       |
  554|   237k|  if(isString())
  ------------------
  |  Branch (554:6): [True: 233k, False: 3.45k]
  ------------------
  555|   233k|  {
  556|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  557|       |    {
  558|       |      if(auto out = stringToNumber<T>())
  559|       |      {
  560|       |        return out.value();
  561|       |      }
  562|       |      else
  563|       |      {
  564|       |        return out;
  565|       |      }
  566|       |    }
  567|   233k|  }
  568|       |
  569|   237k|  if(auto res = convert<T>())
  ------------------
  |  Branch (569:11): [True: 237k, False: 0]
  ------------------
  570|   237k|  {
  571|   237k|    return std::move(res.value());
  572|   237k|  }
  573|      0|  else
  574|      0|  {
  575|      0|    return res;
  576|      0|  }
  577|   237k|}
_ZNK2BT3Any7convertINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEN6nonstd13expected_lite8expectedIT_S7_EEPNSt9enable_ifIXsr3std7is_sameISB_S7_EE5valueEvE4typeE:
  405|   237k|{
  406|   237k|  const auto& type = _any.type();
  407|       |
  408|   237k|  if(type == typeid(SafeAny::SimpleString))
  ------------------
  |  Branch (408:6): [True: 233k, False: 3.45k]
  ------------------
  409|   233k|  {
  410|   233k|    return linb::any_cast<SafeAny::SimpleString>(_any).toStdString();
  411|   233k|  }
  412|  3.45k|  else if(type == typeid(int64_t))
  ------------------
  |  Branch (412:11): [True: 934, False: 2.52k]
  ------------------
  413|    934|  {
  414|    934|    return std::to_string(linb::any_cast<int64_t>(_any));
  415|    934|  }
  416|  2.52k|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (416:11): [True: 0, False: 2.52k]
  ------------------
  417|      0|  {
  418|      0|    return std::to_string(linb::any_cast<uint64_t>(_any));
  419|      0|  }
  420|  2.52k|  else if(type == typeid(double))
  ------------------
  |  Branch (420:11): [True: 2.52k, False: 0]
  ------------------
  421|  2.52k|  {
  422|  2.52k|    return std::to_string(linb::any_cast<double>(_any));
  423|  2.52k|  }
  424|       |
  425|      0|  return nonstd::make_unexpected(errorMsg<DST>());
  426|   237k|}
_ZNK2BT3Any6isTypeIN7SafeAny12SimpleStringEEEbv:
  148|    646|  {
  149|    646|    return _original_type == typeid(T);
  150|    646|  }
_ZNK2BT3Any4castIN7SafeAny12SimpleStringEEET_v:
  169|  16.9k|  {
  170|  16.9k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 16.9k, False: 0]
  ------------------
  171|  16.9k|    {
  172|  16.9k|      return res.value();
  173|  16.9k|    }
  174|      0|    else
  175|      0|    {
  176|      0|      throw std::runtime_error(res.error());
  177|      0|    }
  178|  16.9k|  }
_ZNK2BT3Any7tryCastIN7SafeAny12SimpleStringEEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  522|  16.9k|{
  523|  16.9k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  524|  16.9k|                                              "can not cast to reference");
  525|       |
  526|  16.9k|  if(_any.empty())
  ------------------
  |  Branch (526:6): [True: 0, False: 16.9k]
  ------------------
  527|      0|  {
  528|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  529|      0|  }
  530|       |
  531|  16.9k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (531:6): [True: 16.9k, False: 0]
  ------------------
  532|  16.9k|  {
  533|  16.9k|    return linb::any_cast<T>(_any);
  534|  16.9k|  }
  535|       |
  536|       |  // special case when the output is an enum.
  537|       |  // We will try first a int conversion
  538|       |  if constexpr(std::is_enum_v<T>)
  539|       |  {
  540|       |    if(isNumber())
  541|       |    {
  542|       |      return static_cast<T>(convert<int>().value());
  543|       |    }
  544|       |    if(isString())
  545|       |    {
  546|       |      if(auto out = stringToNumber<int64_t>())
  547|       |      {
  548|       |        return static_cast<T>(out.value());
  549|       |      }
  550|       |    }
  551|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  552|       |  }
  553|       |
  554|      0|  if(isString())
  ------------------
  |  Branch (554:6): [True: 0, False: 0]
  ------------------
  555|      0|  {
  556|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  557|       |    {
  558|       |      if(auto out = stringToNumber<T>())
  559|       |      {
  560|       |        return out.value();
  561|       |      }
  562|       |      else
  563|       |      {
  564|       |        return out;
  565|       |      }
  566|       |    }
  567|      0|  }
  568|       |
  569|      0|  if(auto res = convert<T>())
  ------------------
  |  Branch (569:11): [True: 0, False: 0]
  ------------------
  570|      0|  {
  571|      0|    return std::move(res.value());
  572|      0|  }
  573|      0|  else
  574|      0|  {
  575|      0|    return res;
  576|      0|  }
  577|      0|}
_ZNK2BT3Any4castIbEET_v:
  169|  2.80k|  {
  170|  2.80k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 2.67k, False: 125]
  ------------------
  171|  2.67k|    {
  172|  2.67k|      return res.value();
  173|  2.67k|    }
  174|    125|    else
  175|    125|    {
  176|    125|      throw std::runtime_error(res.error());
  177|    125|    }
  178|  2.80k|  }
_ZNK2BT3Any7tryCastIbEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  522|  2.80k|{
  523|  2.80k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  524|  2.80k|                                              "can not cast to reference");
  525|       |
  526|  2.80k|  if(_any.empty())
  ------------------
  |  Branch (526:6): [True: 0, False: 2.80k]
  ------------------
  527|      0|  {
  528|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  529|      0|  }
  530|       |
  531|  2.80k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (531:6): [True: 0, False: 2.80k]
  ------------------
  532|      0|  {
  533|      0|    return linb::any_cast<T>(_any);
  534|      0|  }
  535|       |
  536|       |  // special case when the output is an enum.
  537|       |  // We will try first a int conversion
  538|       |  if constexpr(std::is_enum_v<T>)
  539|       |  {
  540|       |    if(isNumber())
  541|       |    {
  542|       |      return static_cast<T>(convert<int>().value());
  543|       |    }
  544|       |    if(isString())
  545|       |    {
  546|       |      if(auto out = stringToNumber<int64_t>())
  547|       |      {
  548|       |        return static_cast<T>(out.value());
  549|       |      }
  550|       |    }
  551|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  552|       |  }
  553|       |
  554|  2.80k|  if(isString())
  ------------------
  |  Branch (554:6): [True: 0, False: 2.80k]
  ------------------
  555|      0|  {
  556|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  557|       |    {
  558|       |      if(auto out = stringToNumber<T>())
  559|       |      {
  560|       |        return out.value();
  561|       |      }
  562|       |      else
  563|       |      {
  564|       |        return out;
  565|       |      }
  566|       |    }
  567|      0|  }
  568|       |
  569|  2.80k|  if(auto res = convert<T>())
  ------------------
  |  Branch (569:11): [True: 2.67k, False: 125]
  ------------------
  570|  2.67k|  {
  571|  2.67k|    return std::move(res.value());
  572|  2.67k|  }
  573|    125|  else
  574|    125|  {
  575|    125|    return res;
  576|    125|  }
  577|  2.80k|}
_ZNK2BT3Any7convertIbEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEPNSt9enable_ifIXsr3std13is_arithmeticIS5_EE5valueEvE4typeE:
  495|  2.80k|{
  496|  2.80k|  using SafeAny::details::convertNumber;
  497|  2.80k|  DST out;
  498|       |
  499|  2.80k|  const auto& type = _any.type();
  500|       |
  501|  2.80k|  if(type == typeid(int64_t))
  ------------------
  |  Branch (501:6): [True: 1.65k, False: 1.14k]
  ------------------
  502|  1.65k|  {
  503|  1.65k|    convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
  504|  1.65k|  }
  505|  1.14k|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (505:11): [True: 0, False: 1.14k]
  ------------------
  506|      0|  {
  507|      0|    convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
  508|      0|  }
  509|  1.14k|  else if(type == typeid(double))
  ------------------
  |  Branch (509:11): [True: 1.14k, False: 0]
  ------------------
  510|  1.14k|  {
  511|  1.14k|    convertNumber<double, DST>(linb::any_cast<double>(_any), out);
  512|  1.14k|  }
  513|      0|  else
  514|      0|  {
  515|      0|    return nonstd::make_unexpected(errorMsg<DST>());
  516|      0|  }
  517|  2.80k|  return out;
  518|  2.80k|}

_ZN7SafeAny12SimpleStringC2ERKS0_:
   33|  1.20M|  SimpleString(const SimpleString& other) : SimpleString(other.data(), other.size())
   34|  1.20M|  {}
_ZNK7SafeAny12SimpleString4dataEv:
   87|  1.66M|  {
   88|  1.66M|    if(isSOO())
  ------------------
  |  Branch (88:8): [True: 1.56M, False: 93.8k]
  ------------------
   89|  1.56M|    {
   90|  1.56M|      return _storage.soo.data;
   91|  1.56M|    }
   92|  93.8k|    else
   93|  93.8k|    {
   94|  93.8k|      return _storage.str.data;
   95|  93.8k|    }
   96|  1.66M|  }
_ZNK7SafeAny12SimpleString5isSOOEv:
  155|  6.49M|  {
  156|  6.49M|    return (_storage.soo.capacity_left & IS_LONG_BIT) == 0;
  157|  6.49M|  }
_ZNK7SafeAny12SimpleString4sizeEv:
   99|  2.11M|  {
  100|  2.11M|    if(isSOO())
  ------------------
  |  Branch (100:8): [True: 1.99M, False: 116k]
  ------------------
  101|  1.99M|    {
  102|  1.99M|      return CAPACITY - _storage.soo.capacity_left;
  103|  1.99M|    }
  104|   116k|    else
  105|   116k|    {
  106|   116k|      return _storage.str.size & LONG_MASK;
  107|   116k|    }
  108|  2.11M|  }
_ZN7SafeAny12SimpleStringC2EPKcm:
   64|  1.58M|  {
   65|  1.58M|    createImpl(input_data, size);
   66|  1.58M|  }
_ZN7SafeAny12SimpleString10createImplEPKcm:
  184|  1.58M|  {
  185|  1.58M|    if(size > MAX_SIZE)
  ------------------
  |  Branch (185:8): [True: 14, False: 1.58M]
  ------------------
  186|     14|    {
  187|     14|      throw std::invalid_argument("size too large for a simple string");
  188|     14|    }
  189|       |
  190|  1.58M|    if(size > CAPACITY)
  ------------------
  |  Branch (190:8): [True: 92.0k, False: 1.49M]
  ------------------
  191|  92.0k|    {
  192|  92.0k|      _storage.str.size = size;
  193|  92.0k|      _storage.soo.capacity_left = IS_LONG_BIT;
  194|  92.0k|      _storage.str.data = new char[size + 1];  // NOLINT(cppcoreguidelines-owning-memory)
  195|  92.0k|      std::memcpy(_storage.str.data, input_data, size);
  196|  92.0k|      _storage.str.data[size] = '\0';
  197|  92.0k|    }
  198|  1.49M|    else
  199|  1.49M|    {
  200|  1.49M|      _storage.soo.capacity_left = uint8_t(CAPACITY - size);
  201|  1.49M|      if(size > 0)
  ------------------
  |  Branch (201:10): [True: 1.38M, False: 116k]
  ------------------
  202|  1.38M|      {
  203|  1.38M|        std::memcpy(_storage.soo.data, input_data, size);
  204|  1.38M|      }
  205|  1.49M|      if(size < CAPACITY)
  ------------------
  |  Branch (205:10): [True: 1.49M, False: 1.55k]
  ------------------
  206|  1.49M|      {
  207|  1.49M|        _storage.soo.data[size] = '\0';
  208|  1.49M|      }
  209|  1.49M|    }
  210|  1.58M|  }
_ZNK7SafeAny12SimpleString11toStdStringB5cxx11Ev:
   78|   440k|  {
   79|   440k|    return size() > 0 ? std::string(data(), size()) : std::string();
  ------------------
  |  Branch (79:12): [True: 437k, False: 3.57k]
  ------------------
   80|   440k|  }
_ZN7SafeAny12SimpleStringD2Ev:
   69|  2.71M|  {
   70|  2.71M|    if(!isSOO())
  ------------------
  |  Branch (70:8): [True: 92.0k, False: 2.62M]
  ------------------
   71|  92.0k|    {
   72|  92.0k|      delete[] _storage.str.data;
   73|  92.0k|    }
   74|  2.71M|    _storage.soo.capacity_left = CAPACITY;
   75|  2.71M|  }
_ZN7SafeAny12SimpleStringC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   27|   380k|  SimpleString(const std::string& str) : SimpleString(str.data(), str.size())
   28|   380k|  {}
_ZN7SafeAny12SimpleStringC2EOS0_:
   46|  1.12M|  SimpleString(SimpleString&& other) noexcept : SimpleString()
   47|  1.12M|  {
   48|  1.12M|    std::swap(_storage, other._storage);
   49|  1.12M|  }
_ZN7SafeAny12SimpleStringC2Ev:
   22|  1.12M|  {
   23|  1.12M|    _storage.soo.capacity_left = CAPACITY;
   24|  1.12M|    _storage.soo.data[0] = '\0';
   25|  1.12M|  }
_ZNK7SafeAny12SimpleStringeqERKS0_:
  111|  2.07k|  {
  112|  2.07k|    const size_t N = size();
  113|  2.07k|    return other.size() == N && std::strncmp(data(), other.data(), N) == 0;
  ------------------
  |  Branch (113:12): [True: 1.54k, False: 524]
  |  Branch (113:33): [True: 902, False: 645]
  ------------------
  114|  2.07k|  }
_ZNK7SafeAny12SimpleStringleERKS0_:
  123|  1.66k|  {
  124|  1.66k|    return !(*this > other);
  125|  1.66k|  }
_ZNK7SafeAny12SimpleStringgeERKS0_:
  128|  1.48k|  {
  129|  1.48k|    return !(*this < other);
  130|  1.48k|  }
_ZNK7SafeAny12SimpleStringltERKS0_:
  133|  3.36k|  {
  134|  3.36k|    const size_t min_size = std::min(size(), other.size());
  135|  3.36k|    int cmp = std::memcmp(data(), other.data(), min_size);
  136|  3.36k|    if(cmp != 0)
  ------------------
  |  Branch (136:8): [True: 1.50k, False: 1.86k]
  ------------------
  137|  1.50k|    {
  138|  1.50k|      return cmp < 0;
  139|  1.50k|    }
  140|  1.86k|    return size() < other.size();
  141|  3.36k|  }
_ZNK7SafeAny12SimpleStringgtERKS0_:
  144|  3.03k|  {
  145|  3.03k|    const size_t min_size = std::min(size(), other.size());
  146|  3.03k|    int cmp = std::memcmp(data(), other.data(), min_size);
  147|  3.03k|    if(cmp != 0)
  ------------------
  |  Branch (147:8): [True: 1.45k, False: 1.57k]
  ------------------
  148|  1.45k|    {
  149|  1.45k|      return cmp > 0;
  150|  1.45k|    }
  151|  1.57k|    return size() > other.size();
  152|  3.03k|  }

_ZN2BT16strings_internal9CatPiecesB5cxx11ESt16initializer_listISt17basic_string_viewIcSt11char_traitsIcEEE:
   38|  6.12k|{
   39|  6.12k|  std::string out;
   40|  6.12k|  AppendPieces(&out, std::move(pieces));
   41|  6.12k|  return out;
   42|  6.12k|}
_ZN2BT16strings_internal12AppendPiecesEPNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESt16initializer_listISt17basic_string_viewIcS4_EE:
   24|  6.12k|{
   25|  6.12k|  size_t size = 0;
   26|  6.12k|  for(const auto& piece : pieces)
  ------------------
  |  Branch (26:25): [True: 26.5k, False: 6.12k]
  ------------------
   27|  26.5k|  {
   28|  26.5k|    size += piece.size();
   29|  26.5k|  }
   30|  6.12k|  dest->reserve(dest->size() + size);
   31|  6.12k|  for(const auto& piece : pieces)
  ------------------
  |  Branch (31:25): [True: 26.5k, False: 6.12k]
  ------------------
   32|  26.5k|  {
   33|  26.5k|    dest->append(piece.data(), piece.size());
   34|  26.5k|  }
   35|  6.12k|}
_ZN2BT6StrCatB5cxx11ERKSt17basic_string_viewIcSt11char_traitsIcEE:
   52|  6.28k|{
   53|  6.28k|  return std::string(a.data(), a.size());
   54|  6.28k|}
_ZN2BT6StrCatB5cxx11ERKSt17basic_string_viewIcSt11char_traitsIcEES5_:
   57|    524|{
   58|    524|  return strings_internal::CatPieces({ a, b });
   59|    524|}
_ZN2BT6StrCatB5cxx11ERKSt17basic_string_viewIcSt11char_traitsIcEES5_S5_:
   63|    152|{
   64|    152|  return strings_internal::CatPieces({ a, b, c });
   65|    152|}
_ZN2BT6StrCatIJA8_cSt17basic_string_viewIcSt11char_traitsIcEEA3_cEEENSt7__cxx1112basic_stringIcS4_SaIcEEERKS5_SC_SC_SC_DpRKT_:
   72|    393|{
   73|    393|  return strings_internal::CatPieces(
   74|    393|      { a, b, c, d, static_cast<const std::string_view&>(args)... });
   75|    393|}
_ZN2BT6StrCatIJEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt17basic_string_viewIcS4_ESA_SA_SA_DpRKT_:
   72|  3.00k|{
   73|  3.00k|  return strings_internal::CatPieces(
   74|  3.00k|      { a, b, c, d, static_cast<const std::string_view&>(args)... });
   75|  3.00k|}
_ZN2BT6StrCatIJA3_cEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt17basic_string_viewIcS5_ESB_SB_SB_DpRKT_:
   72|  1.87k|{
   73|  1.87k|  return strings_internal::CatPieces(
   74|  1.87k|      { a, b, c, d, static_cast<const std::string_view&>(args)... });
   75|  1.87k|}
_ZN2BT6StrCatIJA21_cEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt17basic_string_viewIcS5_ESB_SB_SB_DpRKT_:
   72|     69|{
   73|     69|  return strings_internal::CatPieces(
   74|     69|      { a, b, c, d, static_cast<const std::string_view&>(args)... });
   75|     69|}
_ZN2BT6StrCatIJA4_cEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt17basic_string_viewIcS5_ESB_SB_SB_DpRKT_:
   72|     55|{
   73|     55|  return strings_internal::CatPieces(
   74|     55|      { a, b, c, d, static_cast<const std::string_view&>(args)... });
   75|     55|}
_ZN2BT6StrCatIJNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEA2_cEEES6_RKSt17basic_string_viewIcS4_ESB_SB_SB_DpRKT_:
   72|     55|{
   73|     55|  return strings_internal::CatPieces(
   74|     55|      { a, b, c, d, static_cast<const std::string_view&>(args)... });
   75|     55|}

_ZN2BT11parseDoubleESt17basic_string_viewIcSt11char_traitsIcEERdb:
  208|  4.85k|{
  209|       |#if defined(__cpp_lib_to_chars) && (__cpp_lib_to_chars >= 201611L)
  210|       |  // std::from_chars is locale-independent and thread-safe.
  211|       |  const char* begin = str.data();
  212|       |  const char* end = begin + str.size();
  213|       |  const auto [ptr, ec] = std::from_chars(begin, end, out);
  214|       |  if(ec != std::errc())
  215|       |  {
  216|       |    return false;
  217|       |  }
  218|       |  return !require_full_consumption || ptr == end;
  219|       |#else
  220|       |  // Apple's libc++ lacks the floating-point std::from_chars overload. Reproduce
  221|       |  // its std::chars_format::general semantics with strtod_l under a "C" locale
  222|       |  // created once (thread-safe, no global setlocale mutation), plus a guard that
  223|       |  // rejects the leading whitespace, leading '+', and hex floats that strtod
  224|       |  // would otherwise accept.
  225|  4.85k|  if(str.empty())
  ------------------
  |  Branch (225:6): [True: 0, False: 4.85k]
  ------------------
  226|      0|  {
  227|      0|    return false;
  228|      0|  }
  229|  4.85k|  const char first = str.front();
  230|  4.85k|  if(first == '+' || std::isspace(static_cast<unsigned char>(first)) != 0)
  ------------------
  |  Branch (230:6): [True: 0, False: 4.85k]
  |  Branch (230:22): [True: 0, False: 4.85k]
  ------------------
  231|      0|  {
  232|      0|    return false;
  233|      0|  }
  234|       |  // std::from_chars(general) does not recognise a "0x"/"0X" hex-float prefix; it
  235|       |  // parses only the leading "0" and stops at the 'x'. strtod would consume the
  236|       |  // whole hex float, so emulate from_chars here: the value is 0, and everything
  237|       |  // from the 'x' onward is unparsed (a failure only in the full-consumption case).
  238|  4.85k|  const std::size_t mantissa = (first == '-') ? 1u : 0u;
  ------------------
  |  Branch (238:32): [True: 0, False: 4.85k]
  ------------------
  239|  4.85k|  if(str.size() > mantissa + 1 && str[mantissa] == '0' &&
  ------------------
  |  Branch (239:6): [True: 4.85k, False: 0]
  |  Branch (239:35): [True: 1.15k, False: 3.70k]
  ------------------
  240|  1.15k|     (str[mantissa + 1] == 'x' || str[mantissa + 1] == 'X'))
  ------------------
  |  Branch (240:7): [True: 0, False: 1.15k]
  |  Branch (240:35): [True: 0, False: 1.15k]
  ------------------
  241|      0|  {
  242|      0|    if(require_full_consumption)
  ------------------
  |  Branch (242:8): [True: 0, False: 0]
  ------------------
  243|      0|    {
  244|      0|      return false;
  245|      0|    }
  246|      0|    out = (first == '-') ? -0.0 : 0.0;
  ------------------
  |  Branch (246:11): [True: 0, False: 0]
  ------------------
  247|      0|    return true;
  248|      0|  }
  249|  4.85k|  static ::locale_t c_locale =
  250|  4.85k|      ::newlocale(LC_NUMERIC_MASK, "C", static_cast<::locale_t>(0));
  251|  4.85k|  if(c_locale == static_cast<::locale_t>(0))
  ------------------
  |  Branch (251:6): [True: 0, False: 4.85k]
  ------------------
  252|      0|  {
  253|      0|    return false;
  254|      0|  }
  255|       |  // strtod_l needs a null-terminated buffer.
  256|  4.85k|  const std::string buffer(str.data(), str.size());
  257|  4.85k|  errno = 0;
  258|  4.85k|  char* parse_end = nullptr;
  259|  4.85k|  const double value = ::strtod_l(buffer.c_str(), &parse_end, c_locale);
  260|  4.85k|  if(parse_end == buffer.c_str() || errno == ERANGE)
  ------------------
  |  Branch (260:6): [True: 0, False: 4.85k]
  |  Branch (260:37): [True: 105, False: 4.75k]
  ------------------
  261|    105|  {
  262|    105|    return false;
  263|    105|  }
  264|  4.75k|  if(require_full_consumption && parse_end != buffer.c_str() + buffer.size())
  ------------------
  |  Branch (264:6): [True: 0, False: 4.75k]
  |  Branch (264:34): [True: 0, False: 0]
  ------------------
  265|      0|  {
  266|      0|    return false;
  267|      0|  }
  268|  4.75k|  out = value;
  269|  4.75k|  return true;
  270|  4.75k|#endif
  271|  4.75k|}
_ZN2BT17convertFromStringIdEET_St17basic_string_viewIcSt11char_traitsIcEE:
  275|  4.85k|{
  276|  4.85k|  double result = 0;
  277|  4.85k|  if(!parseDouble(str, result, /*require_full_consumption=*/false))
  ------------------
  |  Branch (277:6): [True: 105, False: 4.75k]
  ------------------
  278|    105|  {
  279|    105|    throw RuntimeError(StrCat("Can't convert string [", str, "] to double"));
  280|    105|  }
  281|  4.75k|  return result;
  282|  4.85k|}
_ZNK2BT8TypeInfo4typeEv:
  500|  39.4k|{
  501|  39.4k|  return type_info_;
  502|  39.4k|}
_ZN2BT9StartWithESt17basic_string_viewIcSt11char_traitsIcEEc:
  654|   288k|{
  655|   288k|  return str.size() >= 1 && str[0] == prefix;
  ------------------
  |  Branch (655:10): [True: 183k, False: 104k]
  |  Branch (655:29): [True: 113k, False: 70.2k]
  ------------------
  656|   288k|}

_ZN2BT10Blackboard12getAnyLockedERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   25|   112k|{
   26|   112k|  if(auto entry = getEntry(key))
  ------------------
  |  Branch (26:11): [True: 111k, False: 524]
  ------------------
   27|   111k|  {
   28|   111k|    return AnyPtrLocked(&entry->value, &entry->entry_mutex);
   29|   111k|  }
   30|    524|  return {};
   31|   112k|}
_ZNK2BT10Blackboard8getEntryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   55|   257k|{
   56|       |  // special syntax: "@" will always refer to the root BB
   57|   257k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (57:6): [True: 110k, False: 146k]
  ------------------
   58|   110k|  {
   59|   110k|    return rootBlackboard()->getEntry(key.substr(1, key.size() - 1));
   60|   110k|  }
   61|       |
   62|   146k|  {
   63|   146k|    const std::shared_lock<std::shared_mutex> storage_lock(storage_mutex_);
   64|   146k|    auto it = storage_.find(key);
   65|   146k|    if(it != storage_.end())
  ------------------
  |  Branch (65:8): [True: 136k, False: 10.0k]
  ------------------
   66|   136k|    {
   67|   136k|      return it->second;
   68|   136k|    }
   69|   146k|  }
   70|       |  // not found. Try autoremapping
   71|  10.0k|  if(auto parent = parent_bb_.lock())
  ------------------
  |  Branch (71:11): [True: 0, False: 10.0k]
  ------------------
   72|      0|  {
   73|      0|    auto remap_it = internal_to_external_.find(key);
   74|      0|    if(remap_it != internal_to_external_.cend())
  ------------------
  |  Branch (74:8): [True: 0, False: 0]
  ------------------
   75|      0|    {
   76|      0|      auto const& new_key = remap_it->second;
   77|      0|      return parent->getEntry(new_key);
   78|      0|    }
   79|      0|    if(autoremapping_ && !IsPrivateKey(key))
  ------------------
  |  Branch (79:8): [True: 0, False: 0]
  |  Branch (79:26): [True: 0, False: 0]
  ------------------
   80|      0|    {
   81|      0|      return parent->getEntry(key);
   82|      0|    }
   83|      0|  }
   84|  10.0k|  return {};
   85|  10.0k|}
_ZN2BT10Blackboard8getEntryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   88|   146k|{
   89|   146k|  return static_cast<const Blackboard&>(*this).getEntry(key);
   90|   146k|}
_ZN2BT10Blackboard9entryInfoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   93|    661|{
   94|    661|  auto entry = getEntry(key);
   95|    661|  return (!entry) ? nullptr : &(entry->info);
  ------------------
  |  Branch (95:10): [True: 0, False: 661]
  ------------------
   96|    661|}
_ZN2BT10Blackboard11createEntryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_8TypeInfoE:
  165|  9.44k|{
  166|  9.44k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (166:6): [True: 3.09k, False: 6.34k]
  ------------------
  167|  3.09k|  {
  168|  3.09k|    if(key.find('@', 1) != std::string::npos)
  ------------------
  |  Branch (168:8): [True: 0, False: 3.09k]
  ------------------
  169|      0|    {
  170|      0|      throw LogicError("Character '@' used multiple times in the key");
  171|      0|    }
  172|  3.09k|    rootBlackboard()->createEntryImpl(key.substr(1, key.size() - 1), info);
  173|  3.09k|  }
  174|  6.34k|  else
  175|  6.34k|  {
  176|  6.34k|    createEntryImpl(key, info);
  177|  6.34k|  }
  178|  9.44k|}
_ZN2BT10Blackboard15createEntryImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_8TypeInfoE:
  284|  31.2k|{
  285|  31.2k|  const std::unique_lock storage_lock(storage_mutex_);
  286|       |  // This function might be called recursively, when we do remapping, because we move
  287|       |  // to the top scope to find already existing  entries
  288|       |
  289|       |  // search if exists already
  290|  31.2k|  auto storage_it = storage_.find(key);
  291|  31.2k|  if(storage_it != storage_.end())
  ------------------
  |  Branch (291:6): [True: 0, False: 31.2k]
  ------------------
  292|      0|  {
  293|      0|    const auto& prev_info = storage_it->second->info;
  294|      0|    if(prev_info.type() != info.type() && prev_info.isStronglyTyped() &&
  ------------------
  |  Branch (294:8): [True: 0, False: 0]
  |  Branch (294:43): [True: 0, False: 0]
  ------------------
  295|      0|       info.isStronglyTyped())
  ------------------
  |  Branch (295:8): [True: 0, False: 0]
  ------------------
  296|      0|    {
  297|      0|      auto msg = StrCat("Blackboard entry [", key,
  298|      0|                        "]: once declared, the type of a port"
  299|      0|                        " shall not change. Previously declared type [",
  300|      0|                        BT::demangle(prev_info.type()), "], current type [",
  301|      0|                        BT::demangle(info.type()), "]");
  302|       |
  303|      0|      throw LogicError(msg);
  304|      0|    }
  305|      0|    return storage_it->second;
  306|      0|  }
  307|       |
  308|       |  // manual remapping first
  309|  31.2k|  auto remapping_it = internal_to_external_.find(key);
  310|  31.2k|  if(remapping_it != internal_to_external_.end())
  ------------------
  |  Branch (310:6): [True: 0, False: 31.2k]
  ------------------
  311|      0|  {
  312|      0|    const auto& remapped_key = remapping_it->second;
  313|      0|    if(auto parent = parent_bb_.lock())
  ------------------
  |  Branch (313:13): [True: 0, False: 0]
  ------------------
  314|      0|    {
  315|      0|      return parent->createEntryImpl(remapped_key, info);
  316|      0|    }
  317|      0|    throw RuntimeError("Missing parent blackboard");
  318|      0|  }
  319|       |  // autoremapping second (excluding private keys)
  320|  31.2k|  if(autoremapping_ && !IsPrivateKey(key))
  ------------------
  |  Branch (320:6): [True: 0, False: 31.2k]
  |  Branch (320:24): [True: 0, False: 0]
  ------------------
  321|      0|  {
  322|      0|    if(auto parent = parent_bb_.lock())
  ------------------
  |  Branch (322:13): [True: 0, False: 0]
  ------------------
  323|      0|    {
  324|      0|      return parent->createEntryImpl(key, info);
  325|      0|    }
  326|      0|    throw RuntimeError("Missing parent blackboard");
  327|      0|  }
  328|       |  // not remapped, not found. Create locally.
  329|       |
  330|  31.2k|  auto entry = std::make_shared<Entry>(info);
  331|       |  // even if empty, let's assign to it a default type
  332|  31.2k|  entry->value = Any(info.type());
  333|  31.2k|  storage_.insert({ key, entry });
  334|  31.2k|  return entry;
  335|  31.2k|}
_ZN2BT10Blackboard14rootBlackboardEv:
  374|  3.09k|{
  375|  3.09k|  auto bb = static_cast<const Blackboard&>(*this).rootBlackboard();
  376|       |  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
  377|  3.09k|  return const_cast<Blackboard*>(bb);
  378|  3.09k|}
_ZNK2BT10Blackboard14rootBlackboardEv:
  381|   113k|{
  382|   113k|  const Blackboard* bb = this;
  383|   113k|  Blackboard::Ptr prev = parent_bb_.lock();
  384|   113k|  while(prev)
  ------------------
  |  Branch (384:9): [True: 0, False: 113k]
  ------------------
  385|      0|  {
  386|      0|    bb = prev.get();
  387|      0|    prev = bb->parent_bb_.lock();
  388|      0|  }
  389|   113k|  return bb;
  390|   113k|}

_ZN2BT9Scripting15parseStatementsERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  422|  12.3k|{
  423|  12.3k|  auto tokens = tokenize(script);
  424|  12.3k|  ScriptParser parser(std::move(tokens));
  425|  12.3k|  return parser.parseAll();
  426|  12.3k|}
_ZN2BT11ParseScriptERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  433|  6.95k|{
  434|  6.95k|  try
  435|  6.95k|  {
  436|  6.95k|    auto exprs = Scripting::parseStatements(script);
  437|  6.95k|    if(exprs.empty())
  ------------------
  |  Branch (437:8): [True: 48, False: 6.90k]
  ------------------
  438|     48|    {
  439|     48|      return nonstd::make_unexpected("Empty Script");
  440|     48|    }
  441|  6.90k|    return [exprs = std::move(exprs), script](Ast::Environment& env) {
  442|  6.90k|      try
  443|  6.90k|      {
  444|  6.90k|        for(size_t i = 0; i < exprs.size() - 1; ++i)
  445|  6.90k|        {
  446|  6.90k|          exprs[i]->evaluate(env);
  447|  6.90k|        }
  448|  6.90k|        return exprs.back()->evaluate(env);
  449|  6.90k|      }
  450|  6.90k|      catch(RuntimeError& err)
  451|  6.90k|      {
  452|  6.90k|        throw RuntimeError(StrCat("Error in script [", script, "]\n", err.what()));
  453|  6.90k|      }
  454|  6.90k|    };
  455|  6.95k|  }
  456|  6.95k|  catch(RuntimeError& err)
  457|  6.95k|  {
  458|  2.97k|    return nonstd::make_unexpected(err.what());
  459|  2.97k|  }
  460|  6.95k|}
_ZN2BT21ParseScriptAndExecuteERNS_3Ast11EnvironmentERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  463|  5.44k|{
  464|  5.44k|  auto executor = ParseScript(script);
  465|  5.44k|  if(executor)
  ------------------
  |  Branch (465:6): [True: 3.93k, False: 1.51k]
  ------------------
  466|  3.93k|  {
  467|  3.93k|    try
  468|  3.93k|    {
  469|  3.93k|      return executor.value()(env);
  470|  3.93k|    }
  471|  3.93k|    catch(RuntimeError& err)
  472|  3.93k|    {
  473|    911|      return nonstd::make_unexpected(err.what());
  474|    911|    }
  475|  3.93k|  }
  476|  1.51k|  return nonstd::make_unexpected(executor.error());
  477|  5.44k|}
_ZN2BT14ValidateScriptERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  480|  5.44k|{
  481|  5.44k|  try
  482|  5.44k|  {
  483|  5.44k|    auto exprs = Scripting::parseStatements(script);
  484|  5.44k|    if(exprs.empty())
  ------------------
  |  Branch (484:8): [True: 24, False: 5.41k]
  ------------------
  485|     24|    {
  486|     24|      return nonstd::make_unexpected("Empty Script");
  487|     24|    }
  488|  5.41k|    return {};
  489|  5.44k|  }
  490|  5.44k|  catch(RuntimeError& err)
  491|  5.44k|  {
  492|  1.48k|    return nonstd::make_unexpected(err.what());
  493|  1.48k|  }
  494|  5.44k|}
_ZN2BT9Scripting12ScriptParserC2ESt6vectorINS0_5TokenESaIS3_EE:
   28|  12.3k|  explicit ScriptParser(std::vector<Token> tokens) : tokens_(std::move(tokens))
   29|  12.3k|  {}
_ZN2BT9Scripting12ScriptParser8parseAllEv:
   32|  12.3k|  {
   33|  12.3k|    std::vector<Ast::expr_ptr> stmts;
   34|  7.46M|    while(!atEnd())
  ------------------
  |  Branch (34:11): [True: 7.44M, False: 12.3k]
  ------------------
   35|  7.44M|    {
   36|  7.44M|      stmts.push_back(parseExpr(0));
   37|       |      // consume optional semicolons between statements
   38|  7.45M|      while(check(TokenType::Semicolon))
  ------------------
  |  Branch (38:13): [True: 10.1k, False: 7.44M]
  ------------------
   39|  10.1k|      {
   40|  10.1k|        advance();
   41|  10.1k|      }
   42|  7.44M|    }
   43|  12.3k|    return stmts;
   44|  12.3k|  }
_ZNK2BT9Scripting12ScriptParser5atEndEv:
   73|  19.1M|  {
   74|  19.1M|    return peek().type == TokenType::EndOfInput;
   75|  19.1M|  }
_ZNK2BT9Scripting12ScriptParser4peekEv:
   60|  47.8M|  {
   61|  47.8M|    return tokens_[current_];
   62|  47.8M|  }
_ZN2BT9Scripting12ScriptParser9parseExprEi:
  256|  9.71M|  {
  257|  9.71M|    auto left = parsePrefix();
  258|       |
  259|  9.79M|    while(true)
  ------------------
  |  Branch (259:11): [True: 9.54M, Folded]
  ------------------
  260|  9.54M|    {
  261|  9.54M|      auto tokType = peek().type;
  262|  9.54M|      int lbp = leftBP(tokType);
  263|  9.54M|      if(lbp < 0 || lbp < minBP)
  ------------------
  |  Branch (263:10): [True: 7.51M, False: 2.02M]
  |  Branch (263:21): [True: 1.87M, False: 157k]
  ------------------
  264|  9.38M|      {
  265|  9.38M|        break;
  266|  9.38M|      }
  267|       |
  268|       |      // Assignment (non-associative: parse once, then break)
  269|   157k|      if(isAssignment(tokType))
  ------------------
  |  Branch (269:10): [True: 67.1k, False: 89.9k]
  ------------------
  270|  67.1k|      {
  271|  67.1k|        left = parseAssignment(std::move(left));
  272|  67.1k|        break;
  273|  67.1k|      }
  274|       |
  275|       |      // Ternary (non-associative: parse once, then break)
  276|  89.9k|      if(tokType == TokenType::Question)
  ------------------
  |  Branch (276:10): [True: 7.04k, False: 82.9k]
  ------------------
  277|  7.04k|      {
  278|  7.04k|        left = parseTernary(std::move(left));
  279|  7.04k|        break;
  280|  7.04k|      }
  281|       |
  282|       |      // Chained comparison
  283|  82.9k|      if(isComparison(tokType))
  ------------------
  |  Branch (283:10): [True: 46.3k, False: 36.6k]
  ------------------
  284|  46.3k|      {
  285|  46.3k|        left = parseChainedComparison(std::move(left));
  286|  46.3k|        continue;
  287|  46.3k|      }
  288|       |
  289|       |      // Regular left-associative binary operator
  290|  36.6k|      const auto& opTok = advance();
  291|       |      // Right BP = LBP + 1 for left-associativity
  292|  36.6k|      auto right = parseExpr(lbp + 1);
  293|  36.6k|      left = makeBinary(std::move(left), opTok.type, std::move(right));
  294|  36.6k|    }
  295|       |
  296|  9.71M|    return left;
  297|  9.71M|  }
_ZN2BT9Scripting12ScriptParser11parsePrefixEv:
  164|  9.71M|  {
  165|  9.71M|    const auto& tok = peek();
  166|       |
  167|       |    // Unary minus
  168|  9.71M|    if(tok.type == TokenType::Minus)
  ------------------
  |  Branch (168:8): [True: 26.5k, False: 9.68M]
  ------------------
  169|  26.5k|    {
  170|  26.5k|      advance();
  171|  26.5k|      auto operand = parseExpr(kPrefixBP);
  172|  26.5k|      return std::make_shared<Ast::ExprUnaryArithmetic>(Ast::ExprUnaryArithmetic::negate,
  173|  26.5k|                                                        std::move(operand));
  174|  26.5k|    }
  175|       |    // Bitwise complement
  176|  9.68M|    if(tok.type == TokenType::Tilde)
  ------------------
  |  Branch (176:8): [True: 44.5k, False: 9.64M]
  ------------------
  177|  44.5k|    {
  178|  44.5k|      advance();
  179|  44.5k|      auto operand = parseExpr(kPrefixBP);
  180|  44.5k|      return std::make_shared<Ast::ExprUnaryArithmetic>(
  181|  44.5k|          Ast::ExprUnaryArithmetic::complement, std::move(operand));
  182|  44.5k|    }
  183|       |    // Logical NOT
  184|  9.64M|    if(tok.type == TokenType::Bang)
  ------------------
  |  Branch (184:8): [True: 12.4k, False: 9.62M]
  ------------------
  185|  12.4k|    {
  186|  12.4k|      advance();
  187|  12.4k|      auto operand = parseExpr(kPrefixBP);
  188|  12.4k|      return std::make_shared<Ast::ExprUnaryArithmetic>(
  189|  12.4k|          Ast::ExprUnaryArithmetic::logical_not, std::move(operand));
  190|  12.4k|    }
  191|       |    // Parenthesized expression
  192|  9.62M|    if(tok.type == TokenType::LeftParen)
  ------------------
  |  Branch (192:8): [True: 176k, False: 9.45M]
  ------------------
  193|   176k|    {
  194|   176k|      advance();
  195|   176k|      auto expr = parseExpr(0);
  196|   176k|      expect(TokenType::RightParen, "expected ')'");
  197|   176k|      return expr;
  198|   176k|    }
  199|       |    // Boolean literal
  200|  9.45M|    if(tok.type == TokenType::Boolean)
  ------------------
  |  Branch (200:8): [True: 1.53k, False: 9.44M]
  ------------------
  201|  1.53k|    {
  202|  1.53k|      advance();
  203|  1.53k|      double val = (tok.text == "true") ? 1.0 : 0.0;
  ------------------
  |  Branch (203:20): [True: 801, False: 735]
  ------------------
  204|  1.53k|      return std::make_shared<Ast::ExprLiteral>(Any(val));
  205|  1.53k|    }
  206|       |    // Integer literal
  207|  9.44M|    if(tok.type == TokenType::Integer)
  ------------------
  |  Branch (207:8): [True: 1.41M, False: 8.03M]
  ------------------
  208|  1.41M|    {
  209|  1.41M|      advance();
  210|  1.41M|      int64_t val = 0;
  211|  1.41M|      const char* first = tok.text.data();
  212|  1.41M|      const char* last = first + tok.text.size();
  213|  1.41M|      if(tok.text.size() > 2 && tok.text[0] == '0' &&
  ------------------
  |  Branch (213:10): [True: 20.8k, False: 1.39M]
  |  Branch (213:33): [True: 3.62k, False: 17.1k]
  ------------------
  214|  3.62k|         (tok.text[1] == 'x' || tok.text[1] == 'X'))
  ------------------
  |  Branch (214:11): [True: 403, False: 3.22k]
  |  Branch (214:33): [True: 2.31k, False: 905]
  ------------------
  215|  2.72k|      {
  216|  2.72k|        std::from_chars(first + 2, last, val, 16);
  217|  2.72k|      }
  218|  1.41M|      else
  219|  1.41M|      {
  220|  1.41M|        std::from_chars(first, last, val, 10);
  221|  1.41M|      }
  222|  1.41M|      return std::make_shared<Ast::ExprLiteral>(Any(val));
  223|  1.41M|    }
  224|       |    // Real literal
  225|  8.03M|    if(tok.type == TokenType::Real)
  ------------------
  |  Branch (225:8): [True: 4.85k, False: 8.02M]
  ------------------
  226|  4.85k|    {
  227|  4.85k|      advance();
  228|  4.85k|      double val = convertFromString<double>(tok.text);
  229|  4.85k|      return std::make_shared<Ast::ExprLiteral>(Any(val));
  230|  4.85k|    }
  231|       |    // String literal
  232|  8.02M|    if(tok.type == TokenType::String)
  ------------------
  |  Branch (232:8): [True: 360k, False: 7.66M]
  ------------------
  233|   360k|    {
  234|   360k|      advance();
  235|   360k|      return std::make_shared<Ast::ExprLiteral>(Any(std::string(tok.text)));
  236|   360k|    }
  237|       |    // Identifier
  238|  7.66M|    if(tok.type == TokenType::Identifier)
  ------------------
  |  Branch (238:8): [True: 7.66M, False: 3.96k]
  ------------------
  239|  7.66M|    {
  240|  7.66M|      advance();
  241|  7.66M|      return std::make_shared<Ast::ExprName>(std::string(tok.text));
  242|  7.66M|    }
  243|       |    // Error token from tokenizer
  244|  3.96k|    if(tok.type == TokenType::Error)
  ------------------
  |  Branch (244:8): [True: 2.09k, False: 1.87k]
  ------------------
  245|  2.09k|    {
  246|  2.09k|      throw RuntimeError(
  247|  2.09k|          StrCat("Invalid token '", tok.text, "' at position ", std::to_string(tok.pos)));
  248|  2.09k|    }
  249|       |
  250|  1.87k|    throw RuntimeError(StrCat("Expected operand at position ", std::to_string(tok.pos),
  251|  1.87k|                              " (got '", tok.text, "')"));
  252|  3.96k|  }
_ZN2BT9Scripting12ScriptParser6expectENS0_9TokenTypeEPKc:
   83|  9.45k|  {
   84|  9.45k|    if(!check(type))
  ------------------
  |  Branch (84:8): [True: 393, False: 9.06k]
  ------------------
   85|    393|    {
   86|    393|      throw RuntimeError(StrCat("Parse error at position ", std::to_string(peek().pos),
   87|    393|                                ": ", msg, " (got '", peek().text, "')"));
   88|    393|    }
   89|  9.06k|    return advance();
   90|  9.45k|  }
_ZN2BT9Scripting12ScriptParser6leftBPENS0_9TokenTypeE:
   97|  9.54M|  {
   98|  9.54M|    switch(type)
   99|  9.54M|    {
  100|       |      // Assignment (level 1, non-associative)
  101|  29.9k|      case TokenType::ColonEqual:
  ------------------
  |  Branch (101:7): [True: 29.9k, False: 9.51M]
  ------------------
  102|  47.2k|      case TokenType::Equal:
  ------------------
  |  Branch (102:7): [True: 17.2k, False: 9.52M]
  ------------------
  103|  61.6k|      case TokenType::PlusEqual:
  ------------------
  |  Branch (103:7): [True: 14.3k, False: 9.53M]
  ------------------
  104|  63.2k|      case TokenType::MinusEqual:
  ------------------
  |  Branch (104:7): [True: 1.67k, False: 9.54M]
  ------------------
  105|  65.0k|      case TokenType::StarEqual:
  ------------------
  |  Branch (105:7): [True: 1.80k, False: 9.54M]
  ------------------
  106|  67.8k|      case TokenType::SlashEqual:
  ------------------
  |  Branch (106:7): [True: 2.71k, False: 9.54M]
  ------------------
  107|  67.8k|        return kAssignmentBP;
  108|       |      // Ternary (level 2, non-associative)
  109|  8.61k|      case TokenType::Question:
  ------------------
  |  Branch (109:7): [True: 8.61k, False: 9.53M]
  ------------------
  110|  8.61k|        return kTernaryBP;
  111|       |      // Logical OR (level 3)
  112|  3.22k|      case TokenType::PipePipe:
  ------------------
  |  Branch (112:7): [True: 3.22k, False: 9.54M]
  ------------------
  113|  3.22k|        return 6;
  114|       |      // Logical AND (level 4)
  115|  2.16k|      case TokenType::AmpAmp:
  ------------------
  |  Branch (115:7): [True: 2.16k, False: 9.54M]
  ------------------
  116|  2.16k|        return 8;
  117|       |      // Comparison (level 5, chainable)
  118|  9.19k|      case TokenType::EqualEqual:
  ------------------
  |  Branch (118:7): [True: 9.19k, False: 9.53M]
  ------------------
  119|  52.3k|      case TokenType::BangEqual:
  ------------------
  |  Branch (119:7): [True: 43.1k, False: 9.50M]
  ------------------
  120|   431k|      case TokenType::Less:
  ------------------
  |  Branch (120:7): [True: 378k, False: 9.16M]
  ------------------
  121|  1.87M|      case TokenType::Greater:
  ------------------
  |  Branch (121:7): [True: 1.43M, False: 8.10M]
  ------------------
  122|  1.87M|      case TokenType::LessEqual:
  ------------------
  |  Branch (122:7): [True: 7.53k, False: 9.53M]
  ------------------
  123|  1.89M|      case TokenType::GreaterEqual:
  ------------------
  |  Branch (123:7): [True: 12.3k, False: 9.53M]
  ------------------
  124|  1.89M|        return kComparisonBP;
  125|       |      // Bitwise OR/XOR (level 6)
  126|  5.48k|      case TokenType::Pipe:
  ------------------
  |  Branch (126:7): [True: 5.48k, False: 9.54M]
  ------------------
  127|  6.53k|      case TokenType::Caret:
  ------------------
  |  Branch (127:7): [True: 1.05k, False: 9.54M]
  ------------------
  128|  6.53k|        return 12;
  129|       |      // Bitwise AND (level 7)
  130|  3.58k|      case TokenType::Ampersand:
  ------------------
  |  Branch (130:7): [True: 3.58k, False: 9.54M]
  ------------------
  131|  3.58k|        return 14;
  132|       |      // Add/Sub/Concat (level 8)
  133|  20.2k|      case TokenType::Plus:
  ------------------
  |  Branch (133:7): [True: 20.2k, False: 9.52M]
  ------------------
  134|  27.2k|      case TokenType::Minus:
  ------------------
  |  Branch (134:7): [True: 6.97k, False: 9.53M]
  ------------------
  135|  42.2k|      case TokenType::DotDot:
  ------------------
  |  Branch (135:7): [True: 14.9k, False: 9.53M]
  ------------------
  136|  42.2k|        return 16;
  137|       |      // Mul/Div (level 9)
  138|  1.27k|      case TokenType::Star:
  ------------------
  |  Branch (138:7): [True: 1.27k, False: 9.54M]
  ------------------
  139|  2.74k|      case TokenType::Slash:
  ------------------
  |  Branch (139:7): [True: 1.46k, False: 9.54M]
  ------------------
  140|  2.74k|        return kMulDivBP;
  141|  7.51M|      default:
  ------------------
  |  Branch (141:7): [True: 7.51M, False: 2.02M]
  ------------------
  142|  7.51M|        return -1;
  143|  9.54M|    }
  144|  9.54M|  }
_ZN2BT9Scripting12ScriptParser12isAssignmentENS0_9TokenTypeE:
  154|   157k|  {
  155|   157k|    return type == TokenType::ColonEqual || type == TokenType::Equal ||
  ------------------
  |  Branch (155:12): [True: 29.9k, False: 127k]
  |  Branch (155:45): [True: 16.7k, False: 110k]
  ------------------
  156|   110k|           type == TokenType::PlusEqual || type == TokenType::MinusEqual ||
  ------------------
  |  Branch (156:12): [True: 14.3k, False: 96.1k]
  |  Branch (156:44): [True: 1.66k, False: 94.5k]
  ------------------
  157|  94.5k|           type == TokenType::StarEqual || type == TokenType::SlashEqual;
  ------------------
  |  Branch (157:12): [True: 1.80k, False: 92.7k]
  |  Branch (157:44): [True: 2.71k, False: 89.9k]
  ------------------
  158|   157k|  }
_ZN2BT9Scripting12ScriptParser15parseAssignmentESt10shared_ptrINS_3Ast8ExprBaseEE:
  300|  67.1k|  {
  301|  67.1k|    const auto& opTok = advance();
  302|  67.1k|    Ast::ExprAssignment::op_t op{};
  303|  67.1k|    switch(opTok.type)
  304|  67.1k|    {
  305|  29.9k|      case TokenType::ColonEqual:
  ------------------
  |  Branch (305:7): [True: 29.9k, False: 37.2k]
  ------------------
  306|  29.9k|        op = Ast::ExprAssignment::assign_create;
  307|  29.9k|        break;
  308|  16.7k|      case TokenType::Equal:
  ------------------
  |  Branch (308:7): [True: 16.7k, False: 50.4k]
  ------------------
  309|  16.7k|        op = Ast::ExprAssignment::assign_existing;
  310|  16.7k|        break;
  311|  14.3k|      case TokenType::PlusEqual:
  ------------------
  |  Branch (311:7): [True: 14.3k, False: 52.8k]
  ------------------
  312|  14.3k|        op = Ast::ExprAssignment::assign_plus;
  313|  14.3k|        break;
  314|  1.66k|      case TokenType::MinusEqual:
  ------------------
  |  Branch (314:7): [True: 1.66k, False: 65.5k]
  ------------------
  315|  1.66k|        op = Ast::ExprAssignment::assign_minus;
  316|  1.66k|        break;
  317|  1.80k|      case TokenType::StarEqual:
  ------------------
  |  Branch (317:7): [True: 1.80k, False: 65.3k]
  ------------------
  318|  1.80k|        op = Ast::ExprAssignment::assign_times;
  319|  1.80k|        break;
  320|  2.71k|      case TokenType::SlashEqual:
  ------------------
  |  Branch (320:7): [True: 2.71k, False: 64.4k]
  ------------------
  321|  2.71k|        op = Ast::ExprAssignment::assign_div;
  322|  2.71k|        break;
  323|      0|      default:
  ------------------
  |  Branch (323:7): [True: 0, False: 67.1k]
  ------------------
  324|      0|        throw RuntimeError("Internal error: unexpected assignment op");
  325|  67.1k|    }
  326|       |    // Parse RHS -- use minBP=0 to allow full expression
  327|  67.1k|    auto right = parseExpr(0);
  328|  67.1k|    return std::make_shared<Ast::ExprAssignment>(std::move(left), op, std::move(right));
  329|  67.1k|  }
_ZN2BT9Scripting12ScriptParser12parseTernaryESt10shared_ptrINS_3Ast8ExprBaseEE:
  332|  7.04k|  {
  333|  7.04k|    advance();                     // consume '?'
  334|  7.04k|    auto thenExpr = parseExpr(0);  // full expression inside
  335|  7.04k|    expect(TokenType::Colon, "expected ':' in ternary expression");
  336|  7.04k|    auto elseExpr = parseExpr(kTernaryBP);
  337|  7.04k|    return std::make_shared<Ast::ExprIf>(std::move(condition), std::move(thenExpr),
  338|  7.04k|                                         std::move(elseExpr));
  339|  7.04k|  }
_ZN2BT9Scripting12ScriptParser12isComparisonENS0_9TokenTypeE:
  147|  2.01M|  {
  148|  2.01M|    return type == TokenType::EqualEqual || type == TokenType::BangEqual ||
  ------------------
  |  Branch (148:12): [True: 13.4k, False: 1.99M]
  |  Branch (148:45): [True: 47.2k, False: 1.95M]
  ------------------
  149|  1.95M|           type == TokenType::Less || type == TokenType::Greater ||
  ------------------
  |  Branch (149:12): [True: 387k, False: 1.56M]
  |  Branch (149:39): [True: 1.45M, False: 111k]
  ------------------
  150|   111k|           type == TokenType::LessEqual || type == TokenType::GreaterEqual;
  ------------------
  |  Branch (150:12): [True: 12.1k, False: 99.5k]
  |  Branch (150:44): [True: 20.7k, False: 78.8k]
  ------------------
  151|  2.01M|  }
_ZN2BT9Scripting12ScriptParser22parseChainedComparisonESt10shared_ptrINS_3Ast8ExprBaseEE:
  342|  46.3k|  {
  343|  46.3k|    auto node = std::make_shared<Ast::ExprComparison>();
  344|  46.3k|    node->operands.push_back(std::move(first));
  345|       |
  346|  1.93M|    while(isComparison(peek().type))
  ------------------
  |  Branch (346:11): [True: 1.88M, False: 46.3k]
  ------------------
  347|  1.88M|    {
  348|  1.88M|      node->ops.push_back(mapComparisonOp(advance().type));
  349|       |      // Parse the next operand above comparison level
  350|       |      // so that arithmetic binds tighter
  351|  1.88M|      node->operands.push_back(parseExpr(kComparisonBP + 1));
  352|  1.88M|    }
  353|  46.3k|    return node;
  354|  46.3k|  }
_ZN2BT9Scripting12ScriptParser15mapComparisonOpENS0_9TokenTypeE:
  357|  1.88M|  {
  358|  1.88M|    switch(type)
  359|  1.88M|    {
  360|  9.01k|      case TokenType::EqualEqual:
  ------------------
  |  Branch (360:7): [True: 9.01k, False: 1.87M]
  ------------------
  361|  9.01k|        return Ast::ExprComparison::equal;
  362|  42.9k|      case TokenType::BangEqual:
  ------------------
  |  Branch (362:7): [True: 42.9k, False: 1.84M]
  ------------------
  363|  42.9k|        return Ast::ExprComparison::not_equal;
  364|   375k|      case TokenType::Less:
  ------------------
  |  Branch (364:7): [True: 375k, False: 1.51M]
  ------------------
  365|   375k|        return Ast::ExprComparison::less;
  366|  1.43M|      case TokenType::Greater:
  ------------------
  |  Branch (366:7): [True: 1.43M, False: 446k]
  ------------------
  367|  1.43M|        return Ast::ExprComparison::greater;
  368|  7.36k|      case TokenType::LessEqual:
  ------------------
  |  Branch (368:7): [True: 7.36k, False: 1.87M]
  ------------------
  369|  7.36k|        return Ast::ExprComparison::less_equal;
  370|  11.8k|      case TokenType::GreaterEqual:
  ------------------
  |  Branch (370:7): [True: 11.8k, False: 1.87M]
  ------------------
  371|  11.8k|        return Ast::ExprComparison::greater_equal;
  372|      0|      default:
  ------------------
  |  Branch (372:7): [True: 0, False: 1.88M]
  ------------------
  373|      0|        throw RuntimeError("Internal error: not a comparison op");
  374|  1.88M|    }
  375|  1.88M|  }
_ZN2BT9Scripting12ScriptParser10makeBinaryESt10shared_ptrINS_3Ast8ExprBaseEENS0_9TokenTypeES5_:
  379|  35.3k|  {
  380|  35.3k|    Ast::ExprBinaryArithmetic::op_t op{};
  381|  35.3k|    switch(opType)
  382|  35.3k|    {
  383|  12.3k|      case TokenType::Plus:
  ------------------
  |  Branch (383:7): [True: 12.3k, False: 22.9k]
  ------------------
  384|  12.3k|        op = Ast::ExprBinaryArithmetic::plus;
  385|  12.3k|        break;
  386|  3.62k|      case TokenType::Minus:
  ------------------
  |  Branch (386:7): [True: 3.62k, False: 31.7k]
  ------------------
  387|  3.62k|        op = Ast::ExprBinaryArithmetic::minus;
  388|  3.62k|        break;
  389|    660|      case TokenType::Star:
  ------------------
  |  Branch (389:7): [True: 660, False: 34.7k]
  ------------------
  390|    660|        op = Ast::ExprBinaryArithmetic::times;
  391|    660|        break;
  392|    888|      case TokenType::Slash:
  ------------------
  |  Branch (392:7): [True: 888, False: 34.4k]
  ------------------
  393|    888|        op = Ast::ExprBinaryArithmetic::div;
  394|    888|        break;
  395|  10.0k|      case TokenType::DotDot:
  ------------------
  |  Branch (395:7): [True: 10.0k, False: 25.3k]
  ------------------
  396|  10.0k|        op = Ast::ExprBinaryArithmetic::concat;
  397|  10.0k|        break;
  398|  1.47k|      case TokenType::Ampersand:
  ------------------
  |  Branch (398:7): [True: 1.47k, False: 33.9k]
  ------------------
  399|  1.47k|        op = Ast::ExprBinaryArithmetic::bit_and;
  400|  1.47k|        break;
  401|  2.79k|      case TokenType::Pipe:
  ------------------
  |  Branch (401:7): [True: 2.79k, False: 32.5k]
  ------------------
  402|  2.79k|        op = Ast::ExprBinaryArithmetic::bit_or;
  403|  2.79k|        break;
  404|    531|      case TokenType::Caret:
  ------------------
  |  Branch (404:7): [True: 531, False: 34.8k]
  ------------------
  405|    531|        op = Ast::ExprBinaryArithmetic::bit_xor;
  406|    531|        break;
  407|  1.33k|      case TokenType::AmpAmp:
  ------------------
  |  Branch (407:7): [True: 1.33k, False: 34.0k]
  ------------------
  408|  1.33k|        op = Ast::ExprBinaryArithmetic::logic_and;
  409|  1.33k|        break;
  410|  1.65k|      case TokenType::PipePipe:
  ------------------
  |  Branch (410:7): [True: 1.65k, False: 33.7k]
  ------------------
  411|  1.65k|        op = Ast::ExprBinaryArithmetic::logic_or;
  412|  1.65k|        break;
  413|      0|      default:
  ------------------
  |  Branch (413:7): [True: 0, False: 35.3k]
  ------------------
  414|      0|        throw RuntimeError("Internal error: unknown binary operator");
  415|  35.3k|    }
  416|  35.3k|    return std::make_shared<Ast::ExprBinaryArithmetic>(std::move(left), op,
  417|  35.3k|                                                       std::move(right));
  418|  35.3k|  }
_ZNK2BT9Scripting12ScriptParser5checkENS0_9TokenTypeE:
   78|  7.46M|  {
   79|  7.46M|    return peek().type == type;
   80|  7.46M|  }
_ZN2BT9Scripting12ScriptParser7advanceEv:
   65|  11.7M|  {
   66|  11.7M|    const Token& tok = tokens_[current_];
   67|  11.7M|    if(!atEnd())
  ------------------
  |  Branch (67:8): [True: 11.7M, False: 0]
  ------------------
   68|  11.7M|      current_++;
   69|  11.7M|    return tok;
   70|  11.7M|  }
script_parser.cpp:_ZZN2BT11ParseScriptERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENK3$_0clERNS_3Ast11EnvironmentE:
  441|  3.93k|    return [exprs = std::move(exprs), script](Ast::Environment& env) {
  442|  3.93k|      try
  443|  3.93k|      {
  444|   119k|        for(size_t i = 0; i < exprs.size() - 1; ++i)
  ------------------
  |  Branch (444:27): [True: 115k, False: 3.93k]
  ------------------
  445|   115k|        {
  446|   115k|          exprs[i]->evaluate(env);
  447|   115k|        }
  448|  3.93k|        return exprs.back()->evaluate(env);
  449|  3.93k|      }
  450|  3.93k|      catch(RuntimeError& err)
  451|  3.93k|      {
  452|    911|        throw RuntimeError(StrCat("Error in script [", script, "]\n", err.what()));
  453|    911|      }
  454|  3.93k|    };

_ZN2BT9Scripting8tokenizeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  224|  12.3k|{
  225|  12.3k|  std::vector<Token> tokens;
  226|  12.3k|  const size_t len = source.size();
  227|  12.3k|  size_t i = 0;
  228|       |
  229|  43.0M|  while(i < len)
  ------------------
  |  Branch (229:9): [True: 43.0M, False: 12.3k]
  ------------------
  230|  43.0M|  {
  231|  43.0M|    const char c = source[i];
  232|       |
  233|       |    // Skip whitespace (space, tab, newline, carriage return)
  234|  43.0M|    if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
  ------------------
  |  Branch (234:8): [True: 15.5k, False: 43.0M]
  |  Branch (234:20): [True: 4.63k, False: 42.9M]
  |  Branch (234:33): [True: 275k, False: 42.7M]
  |  Branch (234:46): [True: 4.25k, False: 42.7M]
  ------------------
  235|   300k|    {
  236|   300k|      ++i;
  237|   300k|      continue;
  238|   300k|    }
  239|       |
  240|  42.7M|    const size_t start = i;
  241|       |
  242|       |    // Single-quoted string literal
  243|  42.7M|    if(c == '\'')
  ------------------
  |  Branch (243:8): [True: 515k, False: 42.2M]
  ------------------
  244|   515k|    {
  245|   515k|      ++i;
  246|  58.3M|      while(i < len && source[i] != '\'')
  ------------------
  |  Branch (246:13): [True: 58.3M, False: 411]
  |  Branch (246:24): [True: 57.8M, False: 514k]
  ------------------
  247|  57.8M|      {
  248|  57.8M|        ++i;
  249|  57.8M|      }
  250|   515k|      if(i < len)
  ------------------
  |  Branch (250:10): [True: 514k, False: 411]
  ------------------
  251|   514k|      {
  252|       |        // extract content without quotes
  253|   514k|        std::string_view text(&source[start + 1], i - start - 1);
  254|   514k|        tokens.push_back({ TokenType::String, text, start });
  255|   514k|        ++i;  // skip closing quote
  256|   514k|      }
  257|    411|      else
  258|    411|      {
  259|    411|        std::string_view text(&source[start], i - start);
  260|    411|        tokens.push_back({ TokenType::Error, text, start });
  261|    411|      }
  262|   515k|      continue;
  263|   515k|    }
  264|       |
  265|       |    // Number literal (integer or real)
  266|  42.2M|    if(isDigit(c))
  ------------------
  |  Branch (266:8): [True: 4.15M, False: 38.0M]
  ------------------
  267|  4.15M|    {
  268|  4.15M|      NumberResult nr;
  269|  4.15M|      const bool is_hex =
  270|  4.15M|          c == '0' && i + 1 < len && (source[i + 1] == 'x' || source[i + 1] == 'X');
  ------------------
  |  Branch (270:11): [True: 439k, False: 3.71M]
  |  Branch (270:23): [True: 438k, False: 689]
  |  Branch (270:39): [True: 20.1k, False: 418k]
  |  Branch (270:63): [True: 8.06k, False: 410k]
  ------------------
  271|  4.15M|      if(is_hex)
  ------------------
  |  Branch (271:10): [True: 28.2k, False: 4.12M]
  ------------------
  272|  28.2k|      {
  273|  28.2k|        nr = scanHexNumber(source, len, i);
  274|  28.2k|      }
  275|  4.12M|      else
  276|  4.12M|      {
  277|  4.12M|        nr = scanDecimalNumber(source, len, i);
  278|  4.12M|      }
  279|       |
  280|  4.15M|      std::string_view text(&source[start], i - start);
  281|  4.15M|      if(nr.has_error)
  ------------------
  |  Branch (281:10): [True: 306k, False: 3.84M]
  ------------------
  282|   306k|      {
  283|   306k|        tokens.push_back({ TokenType::Error, text, start });
  284|   306k|      }
  285|  3.84M|      else if(nr.is_real)
  ------------------
  |  Branch (285:15): [True: 29.6k, False: 3.82M]
  ------------------
  286|  29.6k|      {
  287|  29.6k|        tokens.push_back({ TokenType::Real, text, start });
  288|  29.6k|      }
  289|  3.82M|      else
  290|  3.82M|      {
  291|  3.82M|        tokens.push_back({ TokenType::Integer, text, start });
  292|  3.82M|      }
  293|  4.15M|      continue;
  294|  4.15M|    }
  295|       |
  296|       |    // Identifier or keyword (true/false)
  297|  38.0M|    if(isIdentStart(c))
  ------------------
  |  Branch (297:8): [True: 11.8M, False: 26.2M]
  ------------------
  298|  11.8M|    {
  299|  11.8M|      ++i;  // consume start character (may not be isIdentChar, e.g. '@')
  300|  63.6M|      while(i < len && isIdentChar(source[i]))
  ------------------
  |  Branch (300:13): [True: 63.6M, False: 2.85k]
  |  Branch (300:24): [True: 51.8M, False: 11.8M]
  ------------------
  301|  51.8M|      {
  302|  51.8M|        ++i;
  303|  51.8M|      }
  304|  11.8M|      if(std::string_view text(&source[start], i - start); text == "true" || text == "fal"
  ------------------
  |  Branch (304:60): [True: 4.52k, False: 11.8M]
  |  Branch (304:78): [True: 1.42k, False: 11.8M]
  ------------------
  305|  11.8M|                                                                                     "se")
  306|  5.94k|      {
  307|  5.94k|        tokens.push_back({ TokenType::Boolean, text, start });
  308|  5.94k|      }
  309|  11.8M|      else
  310|  11.8M|      {
  311|  11.8M|        tokens.push_back({ TokenType::Identifier, text, start });
  312|  11.8M|      }
  313|  11.8M|      continue;
  314|  11.8M|    }
  315|       |
  316|       |    // Two-character operators (check before single-char)
  317|  26.2M|    if(i + 1 < len)
  ------------------
  |  Branch (317:8): [True: 26.2M, False: 2.31k]
  ------------------
  318|  26.2M|    {
  319|  26.2M|      TokenType two_char_type = matchTwoCharOp(c, source[i + 1]);
  320|  26.2M|      if(two_char_type != TokenType::Error)
  ------------------
  |  Branch (320:10): [True: 256k, False: 25.9M]
  ------------------
  321|   256k|      {
  322|   256k|        std::string_view text(&source[start], 2);
  323|   256k|        tokens.push_back({ two_char_type, text, start });
  324|   256k|        i += 2;
  325|   256k|        continue;
  326|   256k|      }
  327|  26.2M|    }
  328|       |
  329|       |    // Single-character operators and delimiters
  330|  25.9M|    std::string_view text(&source[start], 1);
  331|  25.9M|    tokens.push_back({ matchSingleCharOp(c), text, start });
  332|  25.9M|    ++i;
  333|  25.9M|  }
  334|       |
  335|       |  // Sentinel
  336|  12.3k|  tokens.push_back({ TokenType::EndOfInput, {}, i });
  337|  12.3k|  return tokens;
  338|  12.3k|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_17isDigitEc:
   34|  97.2M|{
   35|  97.2M|  return std::isdigit(static_cast<unsigned char>(c)) != 0;
   36|  97.2M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_113scanHexNumberERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmRm:
   59|  28.2k|{
   60|  28.2k|  NumberResult result;
   61|  28.2k|  i += 2;  // skip "0x"/"0X"
   62|  28.2k|  if(i >= len || !isHexDigit(source[i]))
  ------------------
  |  Branch (62:6): [True: 39, False: 28.1k]
  |  Branch (62:18): [True: 16.1k, False: 11.9k]
  ------------------
   63|  16.2k|  {
   64|  16.2k|    result.has_error = true;
   65|  16.2k|  }
   66|  11.9k|  else
   67|  11.9k|  {
   68|  2.73M|    while(i < len && isHexDigit(source[i]))
  ------------------
  |  Branch (68:11): [True: 2.73M, False: 507]
  |  Branch (68:22): [True: 2.72M, False: 11.4k]
  ------------------
   69|  2.72M|    {
   70|  2.72M|      ++i;
   71|  2.72M|    }
   72|  11.9k|  }
   73|       |  // Hex numbers don't support dot or exponent
   74|  28.2k|  if(i < len && (source[i] == '.' || isIdentChar(source[i])))
  ------------------
  |  Branch (74:6): [True: 27.6k, False: 546]
  |  Branch (74:18): [True: 1.58k, False: 26.0k]
  |  Branch (74:38): [True: 12.8k, False: 13.2k]
  ------------------
   75|  14.4k|  {
   76|  14.4k|    result.has_error = true;
   77|  14.4k|    consumeTrailingGarbage(source, len, i);
   78|  14.4k|  }
   79|  28.2k|  return result;
   80|  28.2k|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_110isHexDigitEc:
   39|  2.76M|{
   40|  2.76M|  return std::isxdigit(static_cast<unsigned char>(c)) != 0;
   41|  2.76M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_122consumeTrailingGarbageERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmRm:
   45|  17.1k|{
   46|  74.3k|  while(i < len && (isIdentChar(source[i]) || source[i] == '.'))
  ------------------
  |  Branch (46:9): [True: 74.1k, False: 204]
  |  Branch (46:21): [True: 54.4k, False: 19.7k]
  |  Branch (46:47): [True: 2.79k, False: 16.9k]
  ------------------
   47|  57.2k|  {
   48|  57.2k|    ++i;
   49|  57.2k|  }
   50|  17.1k|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_117scanDecimalNumberERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmRm:
   83|  4.12M|{
   84|  4.12M|  NumberResult result;
   85|       |
   86|       |  // Integer part
   87|  28.7M|  while(i < len && isDigit(source[i]))
  ------------------
  |  Branch (87:9): [True: 28.7M, False: 2.35k]
  |  Branch (87:20): [True: 24.6M, False: 4.12M]
  ------------------
   88|  24.6M|  {
   89|  24.6M|    ++i;
   90|  24.6M|  }
   91|       |  // Fractional part
   92|  4.12M|  if(i < len && source[i] == '.')
  ------------------
  |  Branch (92:6): [True: 4.12M, False: 2.35k]
  |  Branch (92:17): [True: 22.2k, False: 4.10M]
  ------------------
   93|  22.2k|  {
   94|       |    // Distinguish from ".." (concat operator)
   95|  22.2k|    if(i + 1 < len && source[i + 1] == '.')
  ------------------
  |  Branch (95:8): [True: 22.2k, False: 15]
  |  Branch (95:23): [True: 10.6k, False: 11.5k]
  ------------------
   96|  10.6k|    {
   97|       |      // Stop here: "65.." is Integer("65") + DotDot
   98|  10.6k|    }
   99|  11.5k|    else if(i + 1 < len && isDigit(source[i + 1]))
  ------------------
  |  Branch (99:13): [True: 11.5k, False: 15]
  |  Branch (99:28): [True: 8.81k, False: 2.75k]
  ------------------
  100|  8.81k|    {
  101|  8.81k|      result.is_real = true;
  102|  8.81k|      ++i;  // consume '.'
  103|  22.6M|      while(i < len && isDigit(source[i]))
  ------------------
  |  Branch (103:13): [True: 22.6M, False: 156]
  |  Branch (103:24): [True: 22.6M, False: 8.65k]
  ------------------
  104|  22.6M|      {
  105|  22.6M|        ++i;
  106|  22.6M|      }
  107|  8.81k|    }
  108|  2.76k|    else
  109|  2.76k|    {
  110|       |      // "65." or "65.x" -- incomplete real
  111|  2.76k|      result.has_error = true;
  112|  2.76k|      ++i;  // consume the dot
  113|  2.76k|      consumeTrailingGarbage(source, len, i);
  114|  2.76k|    }
  115|  22.2k|  }
  116|       |  // Exponent (only for decimal numbers)
  117|  4.12M|  if(!result.has_error && i < len && (source[i] == 'e' || source[i] == 'E'))
  ------------------
  |  Branch (117:6): [True: 4.12M, False: 2.76k]
  |  Branch (117:27): [True: 4.12M, False: 2.51k]
  |  Branch (117:39): [True: 6.04k, False: 4.11M]
  |  Branch (117:59): [True: 20.0k, False: 4.09M]
  ------------------
  118|  26.0k|  {
  119|  26.0k|    result.is_real = true;
  120|  26.0k|    ++i;  // consume 'e'/'E'
  121|  26.0k|    if(i < len && (source[i] == '+' || source[i] == '-'))
  ------------------
  |  Branch (121:8): [True: 26.0k, False: 33]
  |  Branch (121:20): [True: 1.61k, False: 24.4k]
  |  Branch (121:40): [True: 1.35k, False: 23.0k]
  ------------------
  122|  2.97k|    {
  123|  2.97k|      ++i;  // consume sign
  124|  2.97k|    }
  125|  26.0k|    if(i >= len || !isDigit(source[i]))
  ------------------
  |  Branch (125:8): [True: 72, False: 25.9k]
  |  Branch (125:20): [True: 4.73k, False: 21.2k]
  ------------------
  126|  4.80k|    {
  127|  4.80k|      result.has_error = true;
  128|  4.80k|    }
  129|  21.2k|    else
  130|  21.2k|    {
  131|  3.50M|      while(i < len && isDigit(source[i]))
  ------------------
  |  Branch (131:13): [True: 3.50M, False: 244]
  |  Branch (131:24): [True: 3.48M, False: 21.0k]
  ------------------
  132|  3.48M|      {
  133|  3.48M|        ++i;
  134|  3.48M|      }
  135|  21.2k|    }
  136|  26.0k|  }
  137|       |  // Trailing alpha (e.g. "3foo", "65.43foo")
  138|  4.12M|  if(!result.has_error && i < len && isIdentStart(source[i]))
  ------------------
  |  Branch (138:6): [True: 4.12M, False: 7.57k]
  |  Branch (138:27): [True: 4.11M, False: 2.75k]
  |  Branch (138:38): [True: 278k, False: 3.83M]
  ------------------
  139|   278k|  {
  140|   278k|    result.has_error = true;
  141|  2.69M|    while(i < len && isIdentChar(source[i]))
  ------------------
  |  Branch (141:11): [True: 2.69M, False: 108]
  |  Branch (141:22): [True: 2.41M, False: 278k]
  ------------------
  142|  2.41M|    {
  143|  2.41M|      ++i;
  144|  2.41M|    }
  145|   278k|  }
  146|  4.12M|  return result;
  147|  4.12M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_112isIdentStartEc:
   24|  42.1M|{
   25|  42.1M|  return std::isalpha(static_cast<unsigned char>(c)) != 0 || c == '_' || c == '@';
  ------------------
  |  Branch (25:10): [True: 1.41M, False: 40.7M]
  |  Branch (25:62): [True: 2.68k, False: 40.7M]
  |  Branch (25:74): [True: 10.6M, False: 30.0M]
  ------------------
   26|  42.1M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_111isIdentCharEc:
   29|  66.4M|{
   30|  66.4M|  return std::isalnum(static_cast<unsigned char>(c)) != 0 || c == '_';
  ------------------
  |  Branch (30:10): [True: 54.2M, False: 12.1M]
  |  Branch (30:62): [True: 12.4k, False: 12.1M]
  ------------------
   31|  66.4M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_114matchTwoCharOpEcc:
  150|  26.2M|{
  151|  26.2M|  if(c == '.' && next == '.')
  ------------------
  |  Branch (151:6): [True: 67.6k, False: 26.1M]
  |  Branch (151:18): [True: 35.2k, False: 32.4k]
  ------------------
  152|  35.2k|    return TokenType::DotDot;
  153|  26.1M|  if(c == '&' && next == '&')
  ------------------
  |  Branch (153:6): [True: 18.6k, False: 26.1M]
  |  Branch (153:18): [True: 13.9k, False: 4.66k]
  ------------------
  154|  13.9k|    return TokenType::AmpAmp;
  155|  26.1M|  if(c == '|' && next == '|')
  ------------------
  |  Branch (155:6): [True: 65.5k, False: 26.1M]
  |  Branch (155:18): [True: 7.76k, False: 57.7k]
  ------------------
  156|  7.76k|    return TokenType::PipePipe;
  157|  26.1M|  if(c == '=' && next == '=')
  ------------------
  |  Branch (157:6): [True: 56.3k, False: 26.1M]
  |  Branch (157:18): [True: 11.5k, False: 44.8k]
  ------------------
  158|  11.5k|    return TokenType::EqualEqual;
  159|  26.1M|  if(c == '!' && next == '=')
  ------------------
  |  Branch (159:6): [True: 110k, False: 26.0M]
  |  Branch (159:18): [True: 68.9k, False: 41.8k]
  ------------------
  160|  68.9k|    return TokenType::BangEqual;
  161|  26.0M|  if(c == '<' && next == '=')
  ------------------
  |  Branch (161:6): [True: 404k, False: 25.6M]
  |  Branch (161:18): [True: 18.7k, False: 386k]
  ------------------
  162|  18.7k|    return TokenType::LessEqual;
  163|  26.0M|  if(c == '>' && next == '=')
  ------------------
  |  Branch (163:6): [True: 2.68M, False: 23.3M]
  |  Branch (163:18): [True: 16.9k, False: 2.66M]
  ------------------
  164|  16.9k|    return TokenType::GreaterEqual;
  165|  26.0M|  if(c == ':' && next == '=')
  ------------------
  |  Branch (165:6): [True: 76.4k, False: 25.9M]
  |  Branch (165:18): [True: 57.7k, False: 18.6k]
  ------------------
  166|  57.7k|    return TokenType::ColonEqual;
  167|  25.9M|  if(c == '+' && next == '=')
  ------------------
  |  Branch (167:6): [True: 40.2k, False: 25.9M]
  |  Branch (167:18): [True: 17.0k, False: 23.1k]
  ------------------
  168|  17.0k|    return TokenType::PlusEqual;
  169|  25.9M|  if(c == '-' && next == '=')
  ------------------
  |  Branch (169:6): [True: 205k, False: 25.7M]
  |  Branch (169:18): [True: 2.31k, False: 203k]
  ------------------
  170|  2.31k|    return TokenType::MinusEqual;
  171|  25.9M|  if(c == '*' && next == '=')
  ------------------
  |  Branch (171:6): [True: 5.67k, False: 25.9M]
  |  Branch (171:18): [True: 2.81k, False: 2.86k]
  ------------------
  172|  2.81k|    return TokenType::StarEqual;
  173|  25.9M|  if(c == '/' && next == '=')
  ------------------
  |  Branch (173:6): [True: 10.1k, False: 25.9M]
  |  Branch (173:18): [True: 3.45k, False: 6.64k]
  ------------------
  174|  3.45k|    return TokenType::SlashEqual;
  175|  25.9M|  return TokenType::Error;
  176|  25.9M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_117matchSingleCharOpEc:
  179|  25.9M|{
  180|  25.9M|  switch(c)
  181|  25.9M|  {
  182|  23.1k|    case '+':
  ------------------
  |  Branch (182:5): [True: 23.1k, False: 25.9M]
  ------------------
  183|  23.1k|      return TokenType::Plus;
  184|   203k|    case '-':
  ------------------
  |  Branch (184:5): [True: 203k, False: 25.7M]
  ------------------
  185|   203k|      return TokenType::Minus;
  186|  2.91k|    case '*':
  ------------------
  |  Branch (186:5): [True: 2.91k, False: 25.9M]
  ------------------
  187|  2.91k|      return TokenType::Star;
  188|  6.68k|    case '/':
  ------------------
  |  Branch (188:5): [True: 6.68k, False: 25.9M]
  ------------------
  189|  6.68k|      return TokenType::Slash;
  190|  4.72k|    case '&':
  ------------------
  |  Branch (190:5): [True: 4.72k, False: 25.9M]
  ------------------
  191|  4.72k|      return TokenType::Ampersand;
  192|  57.8k|    case '|':
  ------------------
  |  Branch (192:5): [True: 57.8k, False: 25.9M]
  ------------------
  193|  57.8k|      return TokenType::Pipe;
  194|  5.89k|    case '^':
  ------------------
  |  Branch (194:5): [True: 5.89k, False: 25.9M]
  ------------------
  195|  5.89k|      return TokenType::Caret;
  196|  76.7k|    case '~':
  ------------------
  |  Branch (196:5): [True: 76.7k, False: 25.8M]
  ------------------
  197|  76.7k|      return TokenType::Tilde;
  198|  41.9k|    case '!':
  ------------------
  |  Branch (198:5): [True: 41.9k, False: 25.9M]
  ------------------
  199|  41.9k|      return TokenType::Bang;
  200|   386k|    case '<':
  ------------------
  |  Branch (200:5): [True: 386k, False: 25.5M]
  ------------------
  201|   386k|      return TokenType::Less;
  202|  2.66M|    case '>':
  ------------------
  |  Branch (202:5): [True: 2.66M, False: 23.3M]
  ------------------
  203|  2.66M|      return TokenType::Greater;
  204|  44.8k|    case '=':
  ------------------
  |  Branch (204:5): [True: 44.8k, False: 25.9M]
  ------------------
  205|  44.8k|      return TokenType::Equal;
  206|  22.9k|    case '?':
  ------------------
  |  Branch (206:5): [True: 22.9k, False: 25.9M]
  ------------------
  207|  22.9k|      return TokenType::Question;
  208|  18.7k|    case ':':
  ------------------
  |  Branch (208:5): [True: 18.7k, False: 25.9M]
  ------------------
  209|  18.7k|      return TokenType::Colon;
  210|   233k|    case '(':
  ------------------
  |  Branch (210:5): [True: 233k, False: 25.7M]
  ------------------
  211|   233k|      return TokenType::LeftParen;
  212|  10.8k|    case ')':
  ------------------
  |  Branch (212:5): [True: 10.8k, False: 25.9M]
  ------------------
  213|  10.8k|      return TokenType::RightParen;
  214|  31.1k|    case ';':
  ------------------
  |  Branch (214:5): [True: 31.1k, False: 25.9M]
  ------------------
  215|  31.1k|      return TokenType::Semicolon;
  216|  22.1M|    default:
  ------------------
  |  Branch (216:5): [True: 22.1M, False: 3.83M]
  ------------------
  217|  22.1M|      return TokenType::Error;
  218|  25.9M|  }
  219|  25.9M|}

