LLVMFuzzerTestOneInput:
   13|  5.48k|{
   14|  5.48k|  if(size < 4)
  ------------------
  |  Branch (14:6): [True: 2, False: 5.48k]
  ------------------
   15|      2|  {
   16|      2|    return 0;
   17|      2|  }
   18|       |
   19|  5.48k|  FuzzedDataProvider fuzz_data(data, size);
   20|       |
   21|  5.48k|  try
   22|  5.48k|  {
   23|  5.48k|    BT::Ast::Environment env;
   24|  5.48k|    env.vars = BT::Blackboard::create();
   25|  5.48k|    env.enums = std::make_shared<BT::EnumsTable>();
   26|       |
   27|       |    // Add some test variables to the blackboard
   28|  5.48k|    env.vars->set("test_int", 42);
   29|  5.48k|    env.vars->set("test_double", 3.14);
   30|  5.48k|    env.vars->set("test_bool", true);
   31|  5.48k|    env.vars->set("test_string", std::string("test"));
   32|       |
   33|       |    // Add some test enums
   34|  5.48k|    (*env.enums)["RUNNING"] = 0;
   35|  5.48k|    (*env.enums)["SUCCESS"] = 1;
   36|  5.48k|    (*env.enums)["FAILURE"] = 2;
   37|       |
   38|  5.48k|    std::string script = fuzz_data.ConsumeRandomLengthString();
   39|       |
   40|  5.48k|    auto validation_result = BT::ValidateScript(script);
   41|       |
   42|  5.48k|    if(!validation_result)
  ------------------
  |  Branch (42:8): [True: 1.32k, False: 4.16k]
  ------------------
   43|  1.32k|    {
   44|  1.32k|      auto parsed_script = BT::ParseScript(script);
   45|  1.32k|      if(parsed_script)
  ------------------
  |  Branch (45:10): [True: 0, False: 1.32k]
  ------------------
   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.32k|    }
   67|       |
   68|  5.48k|    BT::ParseScriptAndExecute(env, script);
   69|  5.48k|  }
   70|  5.48k|  catch(const std::exception&)  // NOLINT(bugprone-empty-catch)
   71|  5.48k|  {
   72|       |    // Intentionally empty - fuzzer expects exceptions
   73|    406|  }
   74|       |
   75|  5.48k|  return 0;
   76|  5.48k|}

_ZN2BT23GetAnyFromStringFunctorIiEESt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEEv:
  217|  5.48k|{
  218|       |  if constexpr(std::is_constructible_v<StringView, T>)
  219|       |  {
  220|       |    return [](StringView str) { return Any(str); };
  221|       |  }
  222|       |  else if constexpr(std::is_same_v<BT::AnyTypeAllowed, T> || std::is_enum_v<T>)
  223|       |  {
  224|       |    return {};
  225|       |  }
  226|       |  else
  227|  5.48k|  {
  228|  5.48k|    return [](StringView str) { return Any(convertFromString<T>(str)); };
  229|  5.48k|  }
  230|  5.48k|}
_ZN2BT8PortInfoC2ENS_13PortDirectionESt10type_indexSt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEE:
  411|  16.4k|    : TypeInfo(type_info, conv), direction_(direction)
  412|  16.4k|  {}
_ZN2BT8TypeInfoC2ESt10type_indexSt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEE:
  369|  16.4k|    : type_info_(type_info), converter_(conv), type_str_(BT::demangle(type_info))
  370|  16.4k|  {}
_ZN2BT23GetAnyFromStringFunctorIdEESt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEEv:
  217|  5.48k|{
  218|       |  if constexpr(std::is_constructible_v<StringView, T>)
  219|       |  {
  220|       |    return [](StringView str) { return Any(str); };
  221|       |  }
  222|       |  else if constexpr(std::is_same_v<BT::AnyTypeAllowed, T> || std::is_enum_v<T>)
  223|       |  {
  224|       |    return {};
  225|       |  }
  226|       |  else
  227|  5.48k|  {
  228|  5.48k|    return [](StringView str) { return Any(convertFromString<T>(str)); };
  229|  5.48k|  }
  230|  5.48k|}
_ZN2BT23GetAnyFromStringFunctorIbEESt8functionIFNS_3AnyESt17basic_string_viewIcSt11char_traitsIcEEEEv:
  217|  5.48k|{
  218|       |  if constexpr(std::is_constructible_v<StringView, T>)
  219|       |  {
  220|       |    return [](StringView str) { return Any(str); };
  221|       |  }
  222|       |  else if constexpr(std::is_same_v<BT::AnyTypeAllowed, T> || std::is_enum_v<T>)
  223|       |  {
  224|       |    return {};
  225|       |  }
  226|       |  else
  227|  5.48k|  {
  228|  5.48k|    return [](StringView str) { return Any(convertFromString<T>(str)); };
  229|  5.48k|  }
  230|  5.48k|}
_ZN2BT8PortInfoC2ENS_13PortDirectionE:
  407|  15.1k|    : TypeInfo(), direction_(direction)
  408|  15.1k|  {}
_ZN2BT8TypeInfoC2Ev:
  365|  15.1k|  TypeInfo() : type_info_(typeid(AnyTypeAllowed)), type_str_("AnyTypeAllowed")
  366|  15.1k|  {}
_ZNK2BT8TypeInfo9converterEv:
  393|    673|  {
  394|    673|    return converter_;
  395|    673|  }

_ZN2BT10Blackboard6createESt10shared_ptrIS0_E:
   75|  5.48k|  {
   76|  5.48k|    return std::shared_ptr<Blackboard>(new Blackboard(parent));
   77|  5.48k|  }
_ZN2BT10BlackboardC2ESt10shared_ptrIS0_E:
   41|  5.48k|  Blackboard(Blackboard::Ptr parent) : parent_bb_(parent)
   42|  5.48k|  {}
_ZN2BT10BlackboardD2Ev:
   79|  5.48k|  virtual ~Blackboard() = default;
_ZN2BT10Blackboard3setIiEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_:
  273|  5.48k|{
  274|  5.48k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.48k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.48k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.48k|  auto it = storage_.find(key);
  283|  5.48k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.48k, False: 0]
  ------------------
  284|  5.48k|  {
  285|       |    // create a new entry
  286|  5.48k|    Any new_value(value);
  287|  5.48k|    storage_lock.unlock();
  288|  5.48k|    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.48k|    {
  296|  5.48k|      PortInfo new_port(PortDirection::INOUT, new_value.type(),
  297|  5.48k|                        GetAnyFromStringFunctor<T>());
  298|  5.48k|      entry = createEntryImpl(key, new_port);
  299|  5.48k|    }
  300|       |
  301|       |    // Lock entry_mutex before writing to prevent data races with
  302|       |    // concurrent readers (BUG-1/BUG-8 fix).
  303|  5.48k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.48k|    entry->value = new_value;
  305|  5.48k|    entry->sequence_id++;
  306|  5.48k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.48k|  }
  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.48k|}
_ZN2BT10Blackboard3setIdEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_:
  273|  5.48k|{
  274|  5.48k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.48k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.48k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.48k|  auto it = storage_.find(key);
  283|  5.48k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.48k, False: 0]
  ------------------
  284|  5.48k|  {
  285|       |    // create a new entry
  286|  5.48k|    Any new_value(value);
  287|  5.48k|    storage_lock.unlock();
  288|  5.48k|    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.48k|    {
  296|  5.48k|      PortInfo new_port(PortDirection::INOUT, new_value.type(),
  297|  5.48k|                        GetAnyFromStringFunctor<T>());
  298|  5.48k|      entry = createEntryImpl(key, new_port);
  299|  5.48k|    }
  300|       |
  301|       |    // Lock entry_mutex before writing to prevent data races with
  302|       |    // concurrent readers (BUG-1/BUG-8 fix).
  303|  5.48k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.48k|    entry->value = new_value;
  305|  5.48k|    entry->sequence_id++;
  306|  5.48k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.48k|  }
  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.48k|}
_ZN2BT10Blackboard3setIbEEvRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKT_:
  273|  5.48k|{
  274|  5.48k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.48k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.48k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.48k|  auto it = storage_.find(key);
  283|  5.48k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.48k, False: 0]
  ------------------
  284|  5.48k|  {
  285|       |    // create a new entry
  286|  5.48k|    Any new_value(value);
  287|  5.48k|    storage_lock.unlock();
  288|  5.48k|    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.48k|    {
  296|  5.48k|      PortInfo new_port(PortDirection::INOUT, new_value.type(),
  297|  5.48k|                        GetAnyFromStringFunctor<T>());
  298|  5.48k|      entry = createEntryImpl(key, new_port);
  299|  5.48k|    }
  300|       |
  301|       |    // Lock entry_mutex before writing to prevent data races with
  302|       |    // concurrent readers (BUG-1/BUG-8 fix).
  303|  5.48k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.48k|    entry->value = new_value;
  305|  5.48k|    entry->sequence_id++;
  306|  5.48k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.48k|  }
  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.48k|}
_ZN2BT10Blackboard3setINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEvRKS7_RKT_:
  273|  5.48k|{
  274|  5.48k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (274:6): [True: 0, False: 5.48k]
  ------------------
  275|      0|  {
  276|      0|    rootBlackboard()->set(key.substr(1, key.size() - 1), value);
  277|      0|    return;
  278|      0|  }
  279|  5.48k|  std::shared_lock storage_lock(storage_mutex_);
  280|       |
  281|       |  // check local storage
  282|  5.48k|  auto it = storage_.find(key);
  283|  5.48k|  if(it == storage_.end())
  ------------------
  |  Branch (283:6): [True: 5.48k, False: 0]
  ------------------
  284|  5.48k|  {
  285|       |    // create a new entry
  286|  5.48k|    Any new_value(value);
  287|  5.48k|    storage_lock.unlock();
  288|  5.48k|    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.48k|    {
  292|  5.48k|      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.48k|    std::scoped_lock entry_lock(entry->entry_mutex);
  304|  5.48k|    entry->value = new_value;
  305|  5.48k|    entry->sequence_id++;
  306|  5.48k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  307|  5.48k|  }
  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.48k|}
_ZN2BT10Blackboard5EntryC2ERKNS_8TypeInfoE:
   61|  31.5k|    Entry(const TypeInfo& _info) : info(_info)
   62|  31.5k|    {}
_ZN2BT10Blackboard5EntryD2Ev:
   64|  31.5k|    ~Entry() = default;

_ZNK4linb3any4typeEv:
  176|  1.76M|    {
  177|  1.76M|        return empty()? typeid(void) : this->vtable->type();
  ------------------
  |  Branch (177:16): [True: 4, False: 1.76M]
  ------------------
  178|  1.76M|    }
_ZNK4linb3any5emptyEv:
  169|  11.1M|    {
  170|  11.1M|        return this->vtable == nullptr;
  171|  11.1M|    }
_ZN4linb3anyC2Ev:
   72|  94.9k|        vtable(nullptr)
   73|  94.9k|    {
   74|  94.9k|    }
_ZN4linb3anyD2Ev:
  100|  5.24M|    {
  101|  5.24M|        this->clear();
  102|  5.24M|    }
_ZN4linb3any5clearEv:
  159|  5.24M|    {
  160|  5.24M|        if(!empty())
  ------------------
  |  Branch (160:12): [True: 3.64M, False: 1.60M]
  ------------------
  161|  3.64M|        {
  162|  3.64M|            this->vtable->destroy(storage);
  163|  3.64M|            this->vtable = nullptr;
  164|  3.64M|        }
  165|  5.24M|    }
_ZN4linb8any_castIdEET_RKNS_3anyE:
  468|  16.3k|{
  469|  16.3k|    auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
  470|  16.3k|#ifndef ANY_IMPL_NO_EXCEPTIONS
  471|  16.3k|    if(p == nullptr) throw bad_any_cast();
  ------------------
  |  Branch (471:8): [True: 0, False: 16.3k]
  ------------------
  472|  16.3k|#endif
  473|  16.3k|    return *p;
  474|  16.3k|}
_ZN4linb8any_castIKdEEPKT_PKNS_3anyE:
  510|  16.3k|{
  511|  16.3k|    using T = typename std::decay<ValueType>::type;
  512|       |
  513|  16.3k|#ifndef ANY_IMPL_NO_RTTI
  514|  16.3k|    if (operand && operand->is_typed(typeid(T)))
  ------------------
  |  Branch (514:9): [True: 16.3k, False: 0]
  |  Branch (514:20): [True: 16.3k, False: 0]
  ------------------
  515|       |#else
  516|       |    if (operand && operand->vtable == any::vtable_for_type<T>())
  517|       |#endif
  518|  16.3k|        return operand->cast<ValueType>();
  519|      0|    else
  520|      0|        return nullptr;
  521|  16.3k|}
_ZNK4linb3any8is_typedERKSt9type_info:
  355|   332k|    {
  356|   332k|        return is_same(this->type(), t);
  357|   332k|    }
_ZN4linb3any7is_sameERKSt9type_infoS3_:
  368|   332k|    {
  369|       |#ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
  370|       |        return &a == &b;
  371|       |#else
  372|   332k|        return a == b;
  373|   332k|#endif
  374|   332k|    }
_ZNK4linb3any4castIKdEEPKT_v:
  380|  16.3k|    {
  381|  16.3k|        return requires_allocation<typename std::decay<T>::type>::value?
  ------------------
  |  Branch (381:16): [Folded, False: 16.3k]
  ------------------
  382|      0|            reinterpret_cast<const T*>(storage.dynamic) :
  383|  16.3k|            reinterpret_cast<const T*>(&storage.stack);
  384|  16.3k|    }
_ZN4linb8any_castIN7SafeAny12SimpleStringEEET_RKNS_3anyE:
  468|  59.4k|{
  469|  59.4k|    auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
  470|  59.4k|#ifndef ANY_IMPL_NO_EXCEPTIONS
  471|  59.4k|    if(p == nullptr) throw bad_any_cast();
  ------------------
  |  Branch (471:8): [True: 0, False: 59.4k]
  ------------------
  472|  59.4k|#endif
  473|  59.4k|    return *p;
  474|  59.4k|}
_ZN4linb8any_castIKN7SafeAny12SimpleStringEEEPKT_PKNS_3anyE:
  510|  59.4k|{
  511|  59.4k|    using T = typename std::decay<ValueType>::type;
  512|       |
  513|  59.4k|#ifndef ANY_IMPL_NO_RTTI
  514|  59.4k|    if (operand && operand->is_typed(typeid(T)))
  ------------------
  |  Branch (514:9): [True: 59.4k, False: 0]
  |  Branch (514:20): [True: 59.4k, False: 0]
  ------------------
  515|       |#else
  516|       |    if (operand && operand->vtable == any::vtable_for_type<T>())
  517|       |#endif
  518|  59.4k|        return operand->cast<ValueType>();
  519|      0|    else
  520|      0|        return nullptr;
  521|  59.4k|}
_ZNK4linb3any4castIKN7SafeAny12SimpleStringEEEPKT_v:
  380|  59.4k|    {
  381|  59.4k|        return requires_allocation<typename std::decay<T>::type>::value?
  ------------------
  |  Branch (381:16): [Folded, False: 59.4k]
  ------------------
  382|      0|            reinterpret_cast<const T*>(storage.dynamic) :
  383|  59.4k|            reinterpret_cast<const T*>(&storage.stack);
  384|  59.4k|    }
_ZN4linb8any_castIlEET_RKNS_3anyE:
  468|   256k|{
  469|   256k|    auto p = any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(&operand);
  470|   256k|#ifndef ANY_IMPL_NO_EXCEPTIONS
  471|   256k|    if(p == nullptr) throw bad_any_cast();
  ------------------
  |  Branch (471:8): [True: 0, False: 256k]
  ------------------
  472|   256k|#endif
  473|   256k|    return *p;
  474|   256k|}
_ZN4linb8any_castIKlEEPKT_PKNS_3anyE:
  510|   256k|{
  511|   256k|    using T = typename std::decay<ValueType>::type;
  512|       |
  513|   256k|#ifndef ANY_IMPL_NO_RTTI
  514|   256k|    if (operand && operand->is_typed(typeid(T)))
  ------------------
  |  Branch (514:9): [True: 256k, False: 0]
  |  Branch (514:20): [True: 256k, False: 0]
  ------------------
  515|       |#else
  516|       |    if (operand && operand->vtable == any::vtable_for_type<T>())
  517|       |#endif
  518|   256k|        return operand->cast<ValueType>();
  519|      0|    else
  520|      0|        return nullptr;
  521|   256k|}
_ZNK4linb3any4castIKlEEPKT_v:
  380|   256k|    {
  381|   256k|        return requires_allocation<typename std::decay<T>::type>::value?
  ------------------
  |  Branch (381:16): [Folded, False: 256k]
  ------------------
  382|      0|            reinterpret_cast<const T*>(storage.dynamic) :
  383|   256k|            reinterpret_cast<const T*>(&storage.stack);
  384|   256k|    }
_ZN4linb3anyC2IlvEEOT_:
  110|  1.38M|    {
  111|  1.38M|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|  1.38M|            "T shall satisfy the CopyConstructible requirements.");
  113|  1.38M|        this->construct(std::forward<ValueType>(value));
  114|  1.38M|    }
_ZN4linb3any9constructIlEEvOT_:
  439|  1.38M|    {
  440|  1.38M|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|  1.38M|        this->vtable = vtable_for_type<T>();
  443|       |
  444|  1.38M|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|  1.38M|    }
_ZN4linb3any15vtable_for_typeIlEEPNS0_11vtable_typeEv:
  333|  1.38M|    {
  334|  1.38M|        using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
  335|  1.38M|        static vtable_type table = {
  336|  1.38M|#ifndef ANY_IMPL_NO_RTTI
  337|  1.38M|            VTableType::type,
  338|  1.38M|#endif
  339|  1.38M|            VTableType::destroy,
  340|  1.38M|            VTableType::copy, VTableType::move,
  341|  1.38M|            VTableType::swap,
  342|  1.38M|        };
  343|  1.38M|        return &table;
  344|  1.38M|    }
_ZN4linb3any12vtable_stackIlE4typeEv:
  289|  1.29M|        {
  290|  1.29M|            return typeid(T);
  291|  1.29M|        }
_ZN4linb3any12vtable_stackIlE7destroyERNS0_13storage_unionE:
  295|  4.76M|        {
  296|  4.76M|            reinterpret_cast<T*>(&storage.stack)->~T();
  297|  4.76M|        }
_ZN4linb3any12vtable_stackIlE4copyERKNS0_13storage_unionERS3_:
  300|  1.63M|        {
  301|  1.63M|            new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
  302|  1.63M|        }
_ZN4linb3any12vtable_stackIlE4moveERNS0_13storage_unionES4_:
  305|  1.74M|        {
  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.74M|            new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
  309|  1.74M|            destroy(src);
  310|  1.74M|        }
_ZN4linb3any12vtable_stackIlE4swapERNS0_13storage_unionES4_:
  313|   118k|        {
  314|   118k|            storage_union tmp_storage;
  315|   118k|            move(rhs, tmp_storage);
  316|   118k|            move(lhs, rhs);
  317|   118k|            move(tmp_storage, lhs);
  318|   118k|        }
_ZN4linb3any12do_constructIllEENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|  1.38M|    {
  432|  1.38M|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|  1.38M|    }
_ZN4linb3anyaSERKS0_:
  129|   166k|    {
  130|   166k|        any(rhs).swap(*this);
  131|   166k|        return *this;
  132|   166k|    }
_ZN4linb3anyC2ERKS0_:
   78|  1.98M|        vtable(rhs.vtable)
   79|  1.98M|    {
   80|  1.98M|        if(!rhs.empty())
  ------------------
  |  Branch (80:12): [True: 1.98M, False: 424]
  ------------------
   81|  1.98M|        {
   82|  1.98M|            rhs.vtable->copy(rhs.storage, this->storage);
   83|  1.98M|        }
   84|  1.98M|    }
_ZN4linb3any4swapERS0_:
  183|   207k|    {
  184|   207k|        if(this->vtable != rhs.vtable)
  ------------------
  |  Branch (184:12): [True: 36.5k, False: 170k]
  ------------------
  185|  36.5k|        {
  186|  36.5k|            any tmp(std::move(rhs));
  187|       |
  188|       |            // move from *this to rhs.
  189|  36.5k|            rhs.vtable = this->vtable;
  190|  36.5k|            if(this->vtable != nullptr)
  ------------------
  |  Branch (190:16): [True: 36.5k, False: 0]
  ------------------
  191|  36.5k|            {
  192|  36.5k|                this->vtable->move(this->storage, rhs.storage);
  193|       |                //this->vtable = nullptr; -- unneeded, see below
  194|  36.5k|            }
  195|       |
  196|       |            // move from tmp (previously rhs) to *this.
  197|  36.5k|            this->vtable = tmp.vtable;
  198|  36.5k|            if(tmp.vtable != nullptr)
  ------------------
  |  Branch (198:16): [True: 6.02k, False: 30.4k]
  ------------------
  199|  6.02k|            {
  200|  6.02k|                tmp.vtable->move(tmp.storage, this->storage);
  201|  6.02k|                tmp.vtable = nullptr;
  202|  6.02k|            }
  203|  36.5k|        }
  204|   170k|        else // same types
  205|   170k|        {
  206|   170k|            if(this->vtable != nullptr)
  ------------------
  |  Branch (206:16): [True: 139k, False: 31.5k]
  ------------------
  207|   139k|                this->vtable->swap(this->storage, rhs.storage);
  208|   170k|        }
  209|   207k|    }
_ZN4linb3anyC2EOS0_:
   89|  1.50M|        vtable(rhs.vtable)
   90|  1.50M|    {
   91|  1.50M|        if(!rhs.empty())
  ------------------
  |  Branch (91:12): [True: 1.47M, False: 30.4k]
  ------------------
   92|  1.47M|        {
   93|  1.47M|            rhs.vtable->move(rhs.storage, this->storage);
   94|  1.47M|            rhs.vtable = nullptr;
   95|  1.47M|        }
   96|  1.50M|    }
_ZN4linb3anyaSEOS0_:
  139|  40.2k|    {
  140|  40.2k|        std::move(rhs).swap(*this);
  141|  40.2k|        return *this;
  142|  40.2k|    }
_ZN4linb3anyaSIlvEERS0_OT_:
  150|    856|    {
  151|    856|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  152|    856|            "T shall satisfy the CopyConstructible requirements.");
  153|    856|        any(std::forward<ValueType>(value)).swap(*this);
  154|    856|        return *this;
  155|    856|    }
_ZN4linb3anyaSIdvEERS0_OT_:
  150|    199|    {
  151|    199|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  152|    199|            "T shall satisfy the CopyConstructible requirements.");
  153|    199|        any(std::forward<ValueType>(value)).swap(*this);
  154|    199|        return *this;
  155|    199|    }
_ZN4linb3anyC2IdvEEOT_:
  110|    199|    {
  111|    199|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|    199|            "T shall satisfy the CopyConstructible requirements.");
  113|    199|        this->construct(std::forward<ValueType>(value));
  114|    199|    }
_ZN4linb3any9constructIdEEvOT_:
  439|    199|    {
  440|    199|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|    199|        this->vtable = vtable_for_type<T>();
  443|       |
  444|    199|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|    199|    }
_ZN4linb3any15vtable_for_typeIdEEPNS0_11vtable_typeEv:
  333|   160k|    {
  334|   160k|        using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
  335|   160k|        static vtable_type table = {
  336|   160k|#ifndef ANY_IMPL_NO_RTTI
  337|   160k|            VTableType::type,
  338|   160k|#endif
  339|   160k|            VTableType::destroy,
  340|   160k|            VTableType::copy, VTableType::move,
  341|   160k|            VTableType::swap,
  342|   160k|        };
  343|   160k|        return &table;
  344|   160k|    }
_ZN4linb3any12vtable_stackIdE4typeEv:
  289|   105k|        {
  290|   105k|            return typeid(T);
  291|   105k|        }
_ZN4linb3any12vtable_stackIdE7destroyERNS0_13storage_unionE:
  295|   206k|        {
  296|   206k|            reinterpret_cast<T*>(&storage.stack)->~T();
  297|   206k|        }
_ZN4linb3any12vtable_stackIdE4copyERKNS0_13storage_unionERS3_:
  300|  19.8k|        {
  301|  19.8k|            new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
  302|  19.8k|        }
_ZN4linb3any12vtable_stackIdE4moveERNS0_13storage_unionES4_:
  305|  25.4k|        {
  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.4k|            new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
  309|  25.4k|            destroy(src);
  310|  25.4k|        }
_ZN4linb3any12vtable_stackIdE4swapERNS0_13storage_unionES4_:
  313|  3.02k|        {
  314|  3.02k|            storage_union tmp_storage;
  315|  3.02k|            move(rhs, tmp_storage);
  316|  3.02k|            move(lhs, rhs);
  317|  3.02k|            move(tmp_storage, lhs);
  318|  3.02k|        }
_ZN4linb3any12do_constructIddEENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|    199|    {
  432|    199|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|    199|    }
_ZN4linb3anyC2IRKdvEEOT_:
  110|   160k|    {
  111|   160k|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|   160k|            "T shall satisfy the CopyConstructible requirements.");
  113|   160k|        this->construct(std::forward<ValueType>(value));
  114|   160k|    }
_ZN4linb3any9constructIRKdEEvOT_:
  439|   160k|    {
  440|   160k|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|   160k|        this->vtable = vtable_for_type<T>();
  443|       |
  444|   160k|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|   160k|    }
_ZN4linb3any12do_constructIRKddEENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|   160k|    {
  432|   160k|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|   160k|    }
_ZN4linb3anyC2IN7SafeAny12SimpleStringEvEEOT_:
  110|   117k|    {
  111|   117k|        static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
  112|   117k|            "T shall satisfy the CopyConstructible requirements.");
  113|   117k|        this->construct(std::forward<ValueType>(value));
  114|   117k|    }
_ZN4linb3any9constructIN7SafeAny12SimpleStringEEEvOT_:
  439|   117k|    {
  440|   117k|        using T = typename std::decay<ValueType>::type;
  441|       |
  442|   117k|        this->vtable = vtable_for_type<T>();
  443|       |
  444|   117k|        do_construct<ValueType,T>(std::forward<ValueType>(value));
  445|   117k|    }
_ZN4linb3any15vtable_for_typeIN7SafeAny12SimpleStringEEEPNS0_11vtable_typeEv:
  333|   117k|    {
  334|   117k|        using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
  335|   117k|        static vtable_type table = {
  336|   117k|#ifndef ANY_IMPL_NO_RTTI
  337|   117k|            VTableType::type,
  338|   117k|#endif
  339|   117k|            VTableType::destroy,
  340|   117k|            VTableType::copy, VTableType::move,
  341|   117k|            VTableType::swap,
  342|   117k|        };
  343|   117k|        return &table;
  344|   117k|    }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4typeEv:
  289|   360k|        {
  290|   360k|            return typeid(T);
  291|   360k|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE7destroyERNS0_13storage_unionE:
  295|   613k|        {
  296|   613k|            reinterpret_cast<T*>(&storage.stack)->~T();
  297|   613k|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4copyERKNS0_13storage_unionERS5_:
  300|   325k|        {
  301|   325k|            new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
  302|   325k|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4moveERNS0_13storage_unionES6_:
  305|   169k|        {
  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|   169k|            new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
  309|   169k|            destroy(src);
  310|   169k|        }
_ZN4linb3any12vtable_stackIN7SafeAny12SimpleStringEE4swapERNS0_13storage_unionES6_:
  313|  17.7k|        {
  314|  17.7k|            storage_union tmp_storage;
  315|  17.7k|            move(rhs, tmp_storage);
  316|  17.7k|            move(lhs, rhs);
  317|  17.7k|            move(tmp_storage, lhs);
  318|  17.7k|        }
_ZN4linb3any12do_constructIN7SafeAny12SimpleStringES3_EENSt9enable_ifIXntsr19requires_allocationIT0_EE5valueEvE4typeEOT_:
  431|   117k|    {
  432|   117k|        new (&storage.stack) T(std::forward<ValueType>(value));
  433|   117k|    }

_ZNK6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  5.30k|    {
 2192|  5.30k|        return has_value();
 2193|  5.30k|    }
_ZNK6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  10.6k|    {
 2197|  10.6k|        return contained.has_value();
 2198|  10.6k|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  10.6k|    {
  787|  10.6k|        return m_has_value;
  788|  10.6k|    }
_ZNK6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  6.62k|    {
 2192|  6.62k|        return has_value();
 2193|  6.62k|    }
_ZNK6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  17.2k|    {
 2197|  17.2k|        return contained.has_value();
 2198|  17.2k|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  17.2k|    {
  787|  17.2k|        return m_has_value;
  788|  17.2k|    }
_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|   524k|    : contained( true )
 1928|   524k|    {
 1929|   524k|        contained.construct_value( std::forward<U>( value ) );
 1930|   524k|    }
_ZN6nonstd13expected_lite6detail9storage_tIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|   531k|        : storage_t_impl<T, E>( has_value )
  922|   531k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|   531k|        : m_has_value( has_value )
  674|   531k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOd:
  687|   524k|    {
  688|   524k|        new( &m_value ) value_type( std::move( e ) );
  689|   524k|    }
_ZN6nonstd13expected_lite15make_unexpectedIRA39_KcEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOS7_:
 1566|    183|{
 1567|    183|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|    183|}
_ZN6nonstd13expected_lite15unexpected_typeIPKcEC2IRA39_S2_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS3_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefIS9_E4typeESt10in_place_tEE5valuentsr3std7is_sameISD_S4_EE5valueEiE4typeELi0EEEOS9_:
 1237|    183|    : m_error( std::forward<E2>( error ) )
 1238|    183|    {}
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleIS7_OT_EE5valuesr3std14is_convertibleISE_S7_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISD_EE:
 1977|    183|    : contained( false )
 1978|    183|    {
 1979|    183|        contained.construct_error( std::move( error.error() ) );
 1980|    183|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOS8_:
  714|    366|    {
  715|    366|        new( &m_error ) error_type( std::move( e ) );
  716|    366|    }
_ZNR6nonstd13expected_lite15unexpected_typeIPKcE5errorEv:
 1334|  5.12k|    {
 1335|  5.12k|        return m_error;
 1336|  5.12k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|   531k|    ~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|  7.13k|    : contained( true )
 1928|  7.13k|    {
 1929|  7.13k|        contained.construct_value( std::forward<U>( value ) );
 1930|  7.13k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueERKd:
  682|  7.13k|    {
  683|  7.13k|        new( &m_value ) value_type( e );
  684|  7.13k|    }
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2EOS8_:
 1793|    183|    nsel_constexpr14 expected( expected &&      ) = default;
_ZN6nonstd13expected_lite6detail9storage_tIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2EOS9_:
  932|    183|        : storage_t_impl<T, E>( other.has_value() )
  933|    183|    {
  934|    183|        if ( this->has_value() ) this->construct_value( std::move( other.value() ) );
  ------------------
  |  Branch (934:14): [True: 0, False: 183]
  ------------------
  935|    183|        else                     this->construct_error( std::move( other.error() ) );
  936|    183|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  1.59M|    {
  787|  1.59M|        return m_has_value;
  788|  1.59M|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|   531k|    {
  742|   531k|        return m_value;
  743|   531k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
  771|    366|    {
  772|    366|        return m_error;
  773|    366|    }
_ZNR6nonstd13expected_lite15unexpected_typeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
 1334|  1.32k|    {
 1335|  1.32k|        return m_error;
 1336|  1.32k|    }
_ZNK6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|   531k|    {
 2192|   531k|        return has_value();
 2193|   531k|    }
_ZNK6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  1.59M|    {
 2197|  1.59M|        return contained.has_value();
 2198|  1.59M|    }
_ZNR6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|   531k|    {
 2211|   531k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 531k, False: 0]
  ------------------
 2212|   531k|            ? ( contained.value() )
 2213|   531k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|   531k|    }
_ZNR6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
 2241|    183|    {
 2242|       |        return assert( ! has_value() ), contained.error();
 2243|    183|    }
_ZN6nonstd13expected_lite8expectedIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|   531k|    {
 2038|   531k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 531k, False: 366]
  ------------------
 2039|    366|        else               contained.destruct_error();
 2040|   531k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|   531k|    {
  705|   531k|        m_value.~value_type();
  706|   531k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIdNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|    366|    {
  732|    366|        m_error.~error_type();
  733|    366|    }
_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|  5.19k|    : contained( true )
 1928|  5.19k|    {
 1929|  5.19k|        contained.construct_value( std::forward<U>( value ) );
 1930|  5.19k|    }
_ZN6nonstd13expected_lite6detail9storage_tIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  5.19k|        : storage_t_impl<T, E>( has_value )
  922|  5.19k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  5.19k|        : m_has_value( has_value )
  674|  5.19k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOl:
  687|  5.19k|    {
  688|  5.19k|        new( &m_value ) value_type( std::move( e ) );
  689|  5.19k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  5.19k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  15.5k|    {
  787|  15.5k|        return m_has_value;
  788|  15.5k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  5.19k|    {
  742|  5.19k|        return m_value;
  743|  5.19k|    }
_ZNK6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  5.19k|    {
 2192|  5.19k|        return has_value();
 2193|  5.19k|    }
_ZNK6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  15.5k|    {
 2197|  15.5k|        return contained.has_value();
 2198|  15.5k|    }
_ZNR6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  5.19k|    {
 2211|  5.19k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 5.19k, False: 0]
  ------------------
 2212|  5.19k|            ? ( contained.value() )
 2213|  5.19k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  5.19k|    }
_ZN6nonstd13expected_lite8expectedIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  5.19k|    {
 2038|  5.19k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 5.19k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|  5.19k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIlNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  5.19k|    {
  705|  5.19k|        m_value.~value_type();
  706|  5.19k|    }
_ZN6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  5.30k|    {
 2038|  5.30k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 3.98k, False: 1.32k]
  ------------------
 2039|  1.32k|        else               contained.destruct_error();
 2040|  5.30k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  3.98k|    {
  705|  3.98k|        m_value.~value_type();
  706|  3.98k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|  1.32k|    {
  732|  1.32k|        m_error.~error_type();
  733|  1.32k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  5.30k|    ~storage_t_impl() {}
_ZN6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  6.62k|    {
 2038|  6.62k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 3.98k, False: 2.64k]
  ------------------
 2039|  2.64k|        else               contained.destruct_error();
 2040|  6.62k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  3.98k|    {
  705|  3.98k|        m_value.~value_type();
  706|  3.98k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|  2.64k|    {
  732|  2.64k|        m_error.~error_type();
  733|  2.64k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  6.62k|    ~storage_t_impl() {}
_ZNR6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  3.98k|    {
 2211|  3.98k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 3.98k, False: 0]
  ------------------
 2212|  3.98k|            ? ( contained.value() )
 2213|  3.98k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  3.98k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  3.98k|    {
  742|  3.98k|        return m_value;
  743|  3.98k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
  771|  1.32k|    {
  772|  1.32k|        return m_error;
  773|  1.32k|    }
_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.78k|    : contained( true )
 1928|  2.78k|    {
 1929|  2.78k|        contained.construct_value( std::forward<U>( value ) );
 1930|  2.78k|    }
_ZN6nonstd13expected_lite6detail9storage_tIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  5.08k|        : storage_t_impl<T, E>( has_value )
  922|  5.08k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  5.08k|        : m_has_value( has_value )
  674|  5.08k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOS4_:
  687|  2.78k|    {
  688|  2.78k|        new( &m_value ) value_type( std::move( e ) );
  689|  2.78k|    }
_ZN6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IS9_TnNSt9enable_ifIXaasr3std16is_constructibleIS9_OT_EE5valuesr3std14is_convertibleISE_S9_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISD_EE:
 1977|  1.32k|    : contained( false )
 1978|  1.32k|    {
 1979|  1.32k|        contained.construct_error( std::move( error.error() ) );
 1980|  1.32k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOSA_:
  714|  2.29k|    {
  715|  2.29k|        new( &m_error ) error_type( std::move( e ) );
  716|  2.29k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  5.08k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  5.08k|    {
  787|  5.08k|        return m_has_value;
  788|  5.08k|    }
_ZNK6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  5.08k|    {
 2197|  5.08k|        return contained.has_value();
 2198|  5.08k|    }
_ZN6nonstd13expected_lite15make_unexpectedIRNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOSB_:
 1566|  1.32k|{
 1567|  1.32k|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|  1.32k|}
_ZN6nonstd13expected_lite15unexpected_typeINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IRS7_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS7_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefISC_E4typeESt10in_place_tEE5valuentsr3std7is_sameISG_S8_EE5valueEiE4typeELi0EEEOSC_:
 1237|  1.32k|    : m_error( std::forward<E2>( error ) )
 1238|  1.32k|    {}
_ZN6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  5.08k|    {
 2038|  5.08k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 2.78k, False: 2.29k]
  ------------------
 2039|  2.29k|        else               contained.destruct_error();
 2040|  5.08k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  2.78k|    {
  705|  2.78k|        m_value.~value_type();
  706|  2.78k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_errorEv:
  731|  2.29k|    {
  732|  2.29k|        m_error.~error_type();
  733|  2.29k|    }
_ZNK6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_E9has_valueEv:
 2196|   237k|    {
 2197|   237k|        return contained.has_value();
 2198|   237k|    }
_ZNK6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_EcvbEv:
 2191|  79.2k|    {
 2192|  79.2k|        return has_value();
 2193|  79.2k|    }
_ZNK6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E9has_valueEv:
  786|   237k|    {
  787|   237k|        return m_has_value;
  788|   237k|    }
_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|  79.2k|    : contained( true )
 1928|  79.2k|    {
 1929|  79.2k|        contained.construct_value( std::forward<U>( value ) );
 1930|  79.2k|    }
_ZN6nonstd13expected_lite6detail9storage_tINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_Lb1ELb1EEC2Eb:
  921|  79.2k|        : storage_t_impl<T, E>( has_value )
  922|  79.2k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_EC2Eb:
  673|  79.2k|        : m_has_value( has_value )
  674|  79.2k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E15construct_valueEOS8_:
  687|  79.2k|    {
  688|  79.2k|        new( &m_value ) value_type( std::move( e ) );
  689|  79.2k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_ED2Ev:
  670|  79.2k|    ~storage_t_impl() {}
_ZN6nonstd13expected_lite15make_unexpectedIPKcEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOS6_:
 1566|  4.86k|{
 1567|  4.86k|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|  4.86k|}
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEv:
  677|  3.98k|    {
  678|  3.98k|        new( &m_value ) value_type();
  679|  3.98k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOS9_:
  714|  1.32k|    {
  715|  1.32k|        new( &m_error ) error_type( std::move( e ) );
  716|  1.32k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E5valueEv:
  741|  79.2k|    {
  742|  79.2k|        return m_value;
  743|  79.2k|    }
_ZNR6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_E5valueEv:
 2210|  79.2k|    {
 2211|  79.2k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 79.2k, False: 0]
  ------------------
 2212|  79.2k|            ? ( contained.value() )
 2213|  79.2k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  79.2k|    }
_ZN6nonstd13expected_lite8expectedINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES7_ED2Ev:
 2037|  79.2k|    {
 2038|  79.2k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 79.2k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|  79.2k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES8_E14destruct_valueEv:
  704|  79.2k|    {
  705|  79.2k|        m_value.~value_type();
  706|  79.2k|    }
_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|  15.8k|    : contained( true )
 1928|  15.8k|    {
 1929|  15.8k|        contained.construct_value( std::forward<U>( value ) );
 1930|  15.8k|    }
_ZN6nonstd13expected_lite6detail9storage_tIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  15.8k|        : storage_t_impl<T, E>( has_value )
  922|  15.8k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  15.8k|        : m_has_value( has_value )
  674|  15.8k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOS4_:
  687|  15.8k|    {
  688|  15.8k|        new( &m_value ) value_type( std::move( e ) );
  689|  15.8k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  15.8k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  47.6k|    {
  787|  47.6k|        return m_has_value;
  788|  47.6k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  15.8k|    {
  742|  15.8k|        return m_value;
  743|  15.8k|    }
_ZNK6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  15.8k|    {
 2192|  15.8k|        return has_value();
 2193|  15.8k|    }
_ZNK6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  47.6k|    {
 2197|  47.6k|        return contained.has_value();
 2198|  47.6k|    }
_ZNR6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  15.8k|    {
 2211|  15.8k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 15.8k, False: 0]
  ------------------
 2212|  15.8k|            ? ( contained.value() )
 2213|  15.8k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  15.8k|    }
_ZN6nonstd13expected_lite8expectedIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  15.8k|    {
 2038|  15.8k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 15.8k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|  15.8k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIN7SafeAny12SimpleStringENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  15.8k|    {
  705|  15.8k|        m_value.~value_type();
  706|  15.8k|    }
_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|  4.90k|    : contained( true )
 1928|  4.90k|    {
 1929|  4.90k|        contained.construct_value( std::forward<U>( value ) );
 1930|  4.90k|    }
_ZN6nonstd13expected_lite6detail9storage_tIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  4.90k|        : storage_t_impl<T, E>( has_value )
  922|  4.90k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  4.90k|        : m_has_value( has_value )
  674|  4.90k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOb:
  687|  4.90k|    {
  688|  4.90k|        new( &m_value ) value_type( std::move( e ) );
  689|  4.90k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
  670|  4.90k|    ~storage_t_impl() {}
_ZNK6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
  786|  14.7k|    {
  787|  14.7k|        return m_has_value;
  788|  14.7k|    }
_ZNR6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
  741|  4.90k|    {
  742|  4.90k|        return m_value;
  743|  4.90k|    }
_ZNK6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEcvbEv:
 2191|  4.90k|    {
 2192|  4.90k|        return has_value();
 2193|  4.90k|    }
_ZNK6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE9has_valueEv:
 2196|  14.7k|    {
 2197|  14.7k|        return contained.has_value();
 2198|  14.7k|    }
_ZNR6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5valueEv:
 2210|  4.90k|    {
 2211|  4.90k|        return has_value()
  ------------------
  |  Branch (2211:16): [True: 4.90k, False: 0]
  ------------------
 2212|  4.90k|            ? ( contained.value() )
 2213|  4.90k|            : ( error_traits<error_type>::rethrow( contained.error() ), contained.value() );
 2214|  4.90k|    }
_ZN6nonstd13expected_lite8expectedIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEED2Ev:
 2037|  4.90k|    {
 2038|  4.90k|        if ( has_value() ) contained.destruct_value();
  ------------------
  |  Branch (2038:14): [True: 4.90k, False: 0]
  ------------------
 2039|      0|        else               contained.destruct_error();
 2040|  4.90k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implIbNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE14destruct_valueEv:
  704|  4.90k|    {
  705|  4.90k|        m_value.~value_type();
  706|  4.90k|    }
_ZN6nonstd13expected_lite15make_unexpectedIRA13_KcEENS0_15unexpected_typeINSt5decayIT_E4typeEEEOS7_:
 1566|     78|{
 1567|     78|    return unexpected_type< typename std::decay<E>::type >( std::forward<E>(value) );
 1568|     78|}
_ZN6nonstd13expected_lite15unexpected_typeIPKcEC2IRA13_S2_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS3_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefIS9_E4typeESt10in_place_tEE5valuentsr3std7is_sameISD_S4_EE5valueEiE4typeELi0EEEOS9_:
 1237|     78|    : m_error( std::forward<E2>( error ) )
 1238|     78|    {}
_ZN6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleISF_OT_EE5valuesr3std14is_convertibleISM_SF_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISL_EE:
 1977|  2.64k|    : contained( false )
 1978|  2.64k|    {
 1979|  2.64k|        contained.construct_error( std::move( error.error() ) );
 1980|  2.64k|    }
_ZN6nonstd13expected_lite6detail9storage_tISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  6.62k|        : storage_t_impl<T, E>( has_value )
  922|  6.62k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  6.62k|        : m_has_value( has_value )
  674|  6.62k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_errorEOSG_:
  714|  2.64k|    {
  715|  2.64k|        new( &m_error ) error_type( std::move( e ) );
  716|  2.64k|    }
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.98k|    : contained( true )
 1928|  3.98k|    {
 1929|  3.98k|        contained.construct_value( std::forward<U>( value ) );
 1930|  3.98k|    }
_ZN6nonstd13expected_lite6detail14storage_t_implISt8functionIFN2BT3AnyERNS4_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE15construct_valueEOSA_:
  687|  3.98k|    {
  688|  3.98k|        new( &m_value ) value_type( std::move( e ) );
  689|  3.98k|    }
_ZN6nonstd13expected_lite15unexpected_typeIPKcEC2IS3_TnNSt9enable_ifIXaaaasr3std16is_constructibleIS3_T_EE5valuentsr3std7is_sameINS0_5std2012remove_cvrefIS7_E4typeESt10in_place_tEE5valuentsr3std7is_sameISB_S4_EE5valueEiE4typeELi0EEEOS7_:
 1237|  4.86k|    : m_error( std::forward<E2>( error ) )
 1238|  4.86k|    {}
_ZN6nonstd13expected_lite8expectedIN2BT3AnyENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleIS9_OT_EE5valuesr3std14is_convertibleISG_S9_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISF_EE:
 1977|    978|    : contained( false )
 1978|    978|    {
 1979|    978|        contained.construct_error( std::move( error.error() ) );
 1980|    978|    }
_ZN6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2IPKcTnNSt9enable_ifIXaasr3std16is_constructibleIS8_OT_EE5valuesr3std14is_convertibleISF_S8_EE5valueEiE4typeELi0EEEONS0_15unexpected_typeISE_EE:
 1977|  1.32k|    : contained( false )
 1978|  1.32k|    {
 1979|  1.32k|        contained.construct_error( std::move( error.error() ) );
 1980|  1.32k|    }
_ZN6nonstd13expected_lite6detail9storage_tISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEELb1ELb1EEC2Eb:
  921|  5.30k|        : storage_t_impl<T, E>( has_value )
  922|  5.30k|    {}
_ZN6nonstd13expected_lite6detail14storage_t_implISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2Eb:
  673|  5.30k|        : m_has_value( has_value )
  674|  5.30k|    {}
_ZN6nonstd13expected_lite8expectedISt9monostateNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEC2ILb1ETnNSt9enable_ifIXT_EiE4typeELi0EEEv:
 1787|  3.98k|    : contained( true )
 1788|  3.98k|    {
 1789|  3.98k|        contained.construct_value();
 1790|  3.98k|    }
_ZNR6nonstd13expected_lite8expectedISt8functionIFN2BT3AnyERNS3_3Ast11EnvironmentEEENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEE5errorEv:
 2241|  1.32k|    {
 2242|       |        return assert( ! has_value() ), contained.error();
 2243|  1.32k|    }

_ZN2BT21BehaviorTreeExceptionC2IJNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEEDpRKT_:
   33|  5.60k|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|  5.60k|  {}
_ZNK2BT21BehaviorTreeException4whatEv:
   37|  5.83k|  {
   38|  5.83k|    return message_.c_str();
   39|  5.83k|  }
_ZN2BT12RuntimeErrorC2IJNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEEDpRKT_:
   67|  5.60k|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|  5.60k|  {}
_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|      6|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      6|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA33_cEEEDpRKT_:
   33|      6|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      6|  {}
_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|     38|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|     38|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA47_cEEEDpRKT_:
   33|     38|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|     38|  {}
_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|      4|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      4|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA35_cEEEDpRKT_:
   33|      4|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      4|  {}
_ZN2BT12RuntimeErrorC2IJA74_cEEEDpRKT_:
   67|      9|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|      9|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA74_cEEEDpRKT_:
   33|      9|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|      9|  {}
_ZN2BT12RuntimeErrorC2IJA79_cEEEDpRKT_:
   67|    139|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|    139|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA79_cEEEDpRKT_:
   33|    139|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|    139|  {}
_ZN2BT12RuntimeErrorC2IJA24_cEEEDpRKT_:
   67|     25|  RuntimeError(const SV&... args) : BehaviorTreeException(args...)
   68|     25|  {}
_ZN2BT21BehaviorTreeExceptionC2IJA24_cEEEDpRKT_:
   33|     25|  BehaviorTreeException(const SV&... args) : message_(StrCat(args...))
   34|     25|  {}

_ZN2BT3Ast19ExprUnaryArithmeticC2ENS1_4op_tESt10shared_ptrINS0_8ExprBaseEE:
  118|  14.6k|  explicit ExprUnaryArithmetic(op_t op, expr_ptr e) : op(op), rhs(std::move(e))
  119|  14.6k|  {}
_ZN2BT3Ast8ExprBaseD2Ev:
   57|  6.58M|  virtual ~ExprBase() = default;
_ZNK2BT3Ast19ExprUnaryArithmetic8evaluateERNS0_11EnvironmentE:
  122|  3.86k|  {
  123|  3.86k|    auto rhs_v = rhs->evaluate(env);
  124|  3.86k|    if(rhs_v.isNumber())
  ------------------
  |  Branch (124:8): [True: 3.82k, False: 44]
  ------------------
  125|  3.82k|    {
  126|  3.82k|      const double rv = rhs_v.cast<double>();
  127|  3.82k|      switch(op)
  ------------------
  |  Branch (127:14): [True: 3.81k, False: 11]
  ------------------
  128|  3.82k|      {
  129|  1.29k|        case negate:
  ------------------
  |  Branch (129:9): [True: 1.29k, False: 2.52k]
  ------------------
  130|  1.29k|          return Any(-rv);
  131|    775|        case complement:
  ------------------
  |  Branch (131:9): [True: 775, False: 3.04k]
  ------------------
  132|    775|          if(rv > static_cast<double>(std::numeric_limits<int64_t>::max()) ||
  ------------------
  |  Branch (132:14): [True: 1, False: 774]
  ------------------
  133|    774|             rv < static_cast<double>(std::numeric_limits<int64_t>::min()))
  ------------------
  |  Branch (133:14): [True: 1, False: 773]
  ------------------
  134|      2|          {
  135|      2|            throw RuntimeError("Number out of range for bitwise operation");
  136|      2|          }
  137|    773|          return Any(static_cast<double>(~static_cast<int64_t>(rv)));
  138|  1.74k|        case logical_not:
  ------------------
  |  Branch (138:9): [True: 1.74k, False: 2.08k]
  ------------------
  139|  1.74k|          return Any(static_cast<double>(!static_cast<bool>(rv)));
  140|  3.82k|      }
  141|  3.82k|    }
  142|     44|    else if(rhs_v.isString())
  ------------------
  |  Branch (142:13): [True: 6, False: 38]
  ------------------
  143|      6|    {
  144|      6|      throw RuntimeError("Invalid operator for std::string");
  145|      6|    }
  146|     38|    throw RuntimeError("ExprUnaryArithmetic: undefined");
  147|  3.86k|  }
_ZN2BT3Ast11ExprLiteralC2ENS_3AnyE:
   71|  1.47M|  ExprLiteral(Any v) : value(v)
   72|  1.47M|  {}
_ZNK2BT3Ast11ExprLiteral8evaluateERNS0_11EnvironmentE:
   75|   156k|  {
   76|   156k|    return value;
   77|   156k|  }
_ZN2BT3Ast8ExprNameC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   84|  4.90M|  explicit ExprName(std::string n) : name(std::move(n))
   85|  4.90M|  {}
_ZNK2BT3Ast8ExprName8evaluateERNS0_11EnvironmentE:
   88|   165k|  {
   89|       |    //search first in the enums table
   90|   165k|    if(env.enums)
  ------------------
  |  Branch (90:8): [True: 165k, False: 0]
  ------------------
   91|   165k|    {
   92|   165k|      auto enum_ptr = env.enums->find(name);
   93|   165k|      if(enum_ptr != env.enums->end())
  ------------------
  |  Branch (93:10): [True: 0, False: 165k]
  ------------------
   94|      0|      {
   95|      0|        return Any(double(enum_ptr->second));
   96|      0|      }
   97|   165k|    }
   98|       |    // search now in the variables table
   99|   165k|    auto any_ref = env.vars->getAnyLocked(name);
  100|   165k|    if(!any_ref)
  ------------------
  |  Branch (100:8): [True: 540, False: 164k]
  ------------------
  101|    540|    {
  102|    540|      throw RuntimeError(StrCat("Variable not found: ", name));
  103|    540|    }
  104|   164k|    return *any_ref.get();
  105|   165k|  }
_ZN2BT3Ast14ExprAssignmentC2ESt10shared_ptrINS0_8ExprBaseEENS1_4op_tES4_:
  507|  64.3k|    : op(op), lhs(std::move(_lhs)), rhs(std::move(_rhs))
  508|  64.3k|  {}
_ZNK2BT3Ast14ExprAssignment8evaluateERNS0_11EnvironmentE:
  511|  25.4k|  {
  512|  25.4k|    auto varname = dynamic_cast<ExprName*>(lhs.get());
  513|  25.4k|    if(!varname)
  ------------------
  |  Branch (513:8): [True: 38, False: 25.3k]
  ------------------
  514|     38|    {
  515|     38|      throw RuntimeError("Assignment left operand not a blackboard entry");
  516|     38|    }
  517|  25.3k|    const auto& key = varname->name;
  518|       |
  519|  25.3k|    auto entry = env.vars->getEntry(key);
  520|  25.3k|    if(!entry)
  ------------------
  |  Branch (520:8): [True: 9.71k, False: 15.6k]
  ------------------
  521|  9.71k|    {
  522|       |      // variable doesn't exist, create it if using operator assign_create
  523|  9.71k|      if(op == assign_create)
  ------------------
  |  Branch (523:10): [True: 9.63k, False: 72]
  ------------------
  524|  9.63k|      {
  525|  9.63k|        env.vars->createEntry(key, PortInfo());
  526|  9.63k|        entry = env.vars->getEntry(key);
  527|  9.63k|        if(!entry)
  ------------------
  |  Branch (527:12): [True: 0, False: 9.63k]
  ------------------
  528|      0|        {
  529|      0|          throw LogicError("Bug: report");
  530|      0|        }
  531|  9.63k|      }
  532|     72|      else
  533|     72|      {
  534|       |        // fail otherwise
  535|     72|        auto msg = StrCat("The blackboard entry [", key,
  536|     72|                          "] doesn't exist, yet.\n"
  537|     72|                          "If you want to create a new one, "
  538|     72|                          "use the operator "
  539|     72|                          "[:=] instead of [=]");
  540|     72|        throw RuntimeError(msg);
  541|     72|      }
  542|  9.71k|    }
  543|  25.3k|    auto value = rhs->evaluate(env);
  544|       |
  545|  25.3k|    std::scoped_lock lock(entry->entry_mutex);
  546|  25.3k|    auto* dst_ptr = &entry->value;
  547|       |
  548|  25.3k|    auto errorPrefix = [dst_ptr, &key]() {
  549|  25.3k|      return StrCat("Error assigning a value to entry [", key, "] with type [",
  550|  25.3k|                    BT::demangle(dst_ptr->type()), "]. ");
  551|  25.3k|    };
  552|       |
  553|  25.3k|    if(value.empty())
  ------------------
  |  Branch (553:8): [True: 45, False: 25.2k]
  ------------------
  554|     45|    {
  555|     45|      throw RuntimeError(ErrorNotInit("right", opStr()));
  556|     45|    }
  557|       |
  558|  25.2k|    if(op == assign_create || op == assign_existing)
  ------------------
  |  Branch (558:8): [True: 15.4k, False: 9.79k]
  |  Branch (558:31): [True: 1.74k, False: 8.05k]
  ------------------
  559|  11.1k|    {
  560|       |      // the very fist assignment can come from any type.
  561|       |      // In the future, type check will be done by Any::copyInto
  562|  11.1k|      if(dst_ptr->empty() && entry->info.type() == typeid(AnyTypeAllowed))
  ------------------
  |  Branch (562:10): [True: 8.54k, False: 2.63k]
  |  Branch (562:10): [True: 8.54k, False: 2.63k]
  |  Branch (562:30): [True: 8.54k, False: 0]
  ------------------
  563|  8.54k|      {
  564|  8.54k|        *dst_ptr = value;
  565|  8.54k|      }
  566|  2.63k|      else if(value.isString() && !dst_ptr->isString())
  ------------------
  |  Branch (566:15): [True: 1.73k, False: 899]
  |  Branch (566:35): [True: 673, False: 1.06k]
  ------------------
  567|    673|      {
  568|       |        // special case: string to other type.
  569|       |        // Check if we can use the StringConverter
  570|    673|        auto const str = value.cast<std::string>();
  571|    673|        const auto* entry_info = env.vars->entryInfo(key);
  572|       |
  573|    673|        if(auto converter = entry_info->converter())
  ------------------
  |  Branch (573:17): [True: 0, False: 673]
  ------------------
  574|      0|        {
  575|      0|          *dst_ptr = converter(str);
  576|      0|        }
  577|    673|        else if(dst_ptr->isNumber())
  ------------------
  |  Branch (577:17): [True: 673, False: 0]
  ------------------
  578|    673|        {
  579|    673|          auto num_value = StringToDouble(value, env);
  580|    673|          *dst_ptr = Any(num_value);
  581|    673|        }
  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|    673|      }
  591|  1.96k|      else
  592|  1.96k|      {
  593|  1.96k|        try
  594|  1.96k|        {
  595|  1.96k|          value.copyInto(*dst_ptr);
  596|  1.96k|        }
  597|  1.96k|        catch(std::exception&)
  598|  1.96k|        {
  599|     56|          auto msg = StrCat(errorPrefix(), "\nThe right operand has type [",
  600|     56|                            BT::demangle(value.type()), "] and can't be converted to [",
  601|     56|                            BT::demangle(dst_ptr->type()), "]");
  602|     56|          throw RuntimeError(msg);
  603|     56|        }
  604|  1.96k|      }
  605|  11.1k|      entry->sequence_id++;
  606|  11.1k|      entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  607|  11.1k|      return *dst_ptr;
  608|  11.1k|    }
  609|       |
  610|  14.0k|    if(dst_ptr->empty())
  ------------------
  |  Branch (610:8): [True: 6, False: 14.0k]
  ------------------
  611|      6|    {
  612|      6|      throw RuntimeError(ErrorNotInit("left", opStr()));
  613|      6|    }
  614|       |
  615|       |    // temporary use
  616|  14.0k|    Any temp_variable = *dst_ptr;
  617|       |
  618|  14.0k|    if(value.isNumber())
  ------------------
  |  Branch (618:8): [True: 1.73k, False: 12.3k]
  ------------------
  619|  1.73k|    {
  620|  1.73k|      if(!temp_variable.isNumber())
  ------------------
  |  Branch (620:10): [True: 6, False: 1.72k]
  ------------------
  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.72k|      auto lv = temp_variable.cast<double>();
  627|  1.72k|      auto rv = value.cast<double>();
  628|  1.72k|      switch(op)
  629|  1.72k|      {
  630|    456|        case assign_plus:
  ------------------
  |  Branch (630:9): [True: 456, False: 1.27k]
  ------------------
  631|    456|          temp_variable = Any(lv + rv);
  632|    456|          break;
  633|    445|        case assign_minus:
  ------------------
  |  Branch (633:9): [True: 445, False: 1.28k]
  ------------------
  634|    445|          temp_variable = Any(lv - rv);
  635|    445|          break;
  636|    412|        case assign_times:
  ------------------
  |  Branch (636:9): [True: 412, False: 1.31k]
  ------------------
  637|    412|          temp_variable = Any(lv * rv);
  638|    412|          break;
  639|    412|        case assign_div:
  ------------------
  |  Branch (639:9): [True: 412, False: 1.31k]
  ------------------
  640|    412|          temp_variable = Any(lv / rv);
  641|    412|          break;
  642|      0|        default: {
  ------------------
  |  Branch (642:9): [True: 0, False: 1.72k]
  ------------------
  643|      0|        }
  644|  1.72k|      }
  645|  1.72k|    }
  646|  12.3k|    else if(value.isString())
  ------------------
  |  Branch (646:13): [True: 6.31k, False: 6.02k]
  ------------------
  647|  6.31k|    {
  648|  6.31k|      if(op == assign_plus)
  ------------------
  |  Branch (648:10): [True: 6.31k, False: 4]
  ------------------
  649|  6.31k|      {
  650|  6.31k|        auto lv = temp_variable.cast<std::string>();
  651|  6.31k|        auto rv = value.cast<std::string>();
  652|  6.31k|        temp_variable = Any(lv + rv);
  653|  6.31k|      }
  654|      4|      else
  655|      4|      {
  656|      4|        throw RuntimeError("Operator not supported for strings");
  657|      4|      }
  658|  6.31k|    }
  659|       |
  660|  14.0k|    temp_variable.copyInto(*dst_ptr);
  661|  14.0k|    entry->sequence_id++;
  662|  14.0k|    entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
  663|  14.0k|    return *dst_ptr;
  664|  14.0k|  }
_ZN2BT3Ast12ErrorNotInitB5cxx11EPKcS2_:
   62|     80|{
   63|     80|  return StrCat("The ", side, " operand of the operator [", op_str,
   64|     80|                "] is not initialized");
   65|     80|}
_ZNK2BT3Ast14ExprAssignment5opStrEv:
  485|     51|  {
  486|     51|    switch(op)
  ------------------
  |  Branch (486:12): [True: 51, False: 0]
  ------------------
  487|     51|    {
  488|     29|      case assign_create:
  ------------------
  |  Branch (488:7): [True: 29, False: 22]
  ------------------
  489|     29|        return ":=";
  490|     16|      case assign_existing:
  ------------------
  |  Branch (490:7): [True: 16, False: 35]
  ------------------
  491|     16|        return "=";
  492|      3|      case assign_plus:
  ------------------
  |  Branch (492:7): [True: 3, False: 48]
  ------------------
  493|      3|        return "+=";
  494|      1|      case assign_minus:
  ------------------
  |  Branch (494:7): [True: 1, False: 50]
  ------------------
  495|      1|        return "-=";
  496|      1|      case assign_times:
  ------------------
  |  Branch (496:7): [True: 1, False: 50]
  ------------------
  497|      1|        return "*=";
  498|      1|      case assign_div:
  ------------------
  |  Branch (498:7): [True: 1, False: 50]
  ------------------
  499|      1|        return "/=";
  500|     51|    }
  501|      0|    return "";
  502|     51|  }
_ZN2BT3Ast14StringToDoubleERKNS_3AnyERKNS0_11EnvironmentE:
   32|  7.70k|{
   33|  7.70k|  const auto str = value.cast<std::string>();
   34|  7.70k|  if(str == "true")
  ------------------
  |  Branch (34:6): [True: 197, False: 7.50k]
  ------------------
   35|    197|  {
   36|    197|    return 1.0;
   37|    197|  }
   38|  7.50k|  if(str == "false")
  ------------------
  |  Branch (38:6): [True: 194, False: 7.31k]
  ------------------
   39|    194|  {
   40|    194|    return 0.0;
   41|    194|  }
   42|  7.31k|  if(env.enums)
  ------------------
  |  Branch (42:6): [True: 7.31k, False: 0]
  ------------------
   43|  7.31k|  {
   44|  7.31k|    auto it = env.enums->find(str);
   45|  7.31k|    if(it != env.enums->end())
  ------------------
  |  Branch (45:8): [True: 0, False: 7.31k]
  ------------------
   46|      0|    {
   47|      0|      return it->second;
   48|      0|    }
   49|  7.31k|  }
   50|  7.31k|  return value.cast<double>();
   51|  7.31k|}
_ZZNK2BT3Ast14ExprAssignment8evaluateERNS0_11EnvironmentEENKUlvE_clB5cxx11Ev:
  548|     56|    auto errorPrefix = [dst_ptr, &key]() {
  549|     56|      return StrCat("Error assigning a value to entry [", key, "] with type [",
  550|     56|                    BT::demangle(dst_ptr->type()), "]. ");
  551|     56|    };
_ZN2BT3Ast6ExprIfC2ESt10shared_ptrINS0_8ExprBaseEES4_S4_:
  453|  1.85k|    : condition(std::move(condition)), then(std::move(then)), else_(std::move(else_))
  454|  1.85k|  {}
_ZNK2BT3Ast6ExprIf8evaluateERNS0_11EnvironmentE:
  457|    707|  {
  458|    707|    const auto& v = condition->evaluate(env);
  459|    707|    bool valid = (v.isType<SimpleString>() && v.cast<SimpleString>().size() > 0) ||
  ------------------
  |  Branch (459:19): [True: 0, False: 707]
  |  Branch (459:47): [True: 0, False: 0]
  ------------------
  460|    698|                 (v.cast<double>() != 0.0);
  ------------------
  |  Branch (460:18): [True: 252, False: 446]
  ------------------
  461|    707|    if(valid)
  ------------------
  |  Branch (461:8): [True: 248, False: 459]
  ------------------
  462|    248|    {
  463|    248|      return then->evaluate(env);
  464|    248|    }
  465|    459|    else
  466|    459|    {
  467|    459|      return else_->evaluate(env);
  468|    459|    }
  469|    707|  }
_ZNK2BT3Ast14ExprComparison8evaluateERNS0_11EnvironmentE:
  352|  12.9k|  {
  353|  12.9k|    auto SwitchImpl = [&](const auto& lv, const auto& rv, op_t op) {
  354|  12.9k|      switch(op)
  355|  12.9k|      {
  356|  12.9k|        case equal:
  357|  12.9k|          if(!IsSame(lv, rv))
  358|  12.9k|            return false;
  359|  12.9k|          break;
  360|  12.9k|        case not_equal:
  361|  12.9k|          if(IsSame(lv, rv))
  362|  12.9k|            return false;
  363|  12.9k|          break;
  364|  12.9k|        case less:
  365|  12.9k|          if(lv >= rv)
  366|  12.9k|            return false;
  367|  12.9k|          break;
  368|  12.9k|        case greater:
  369|  12.9k|          if(lv <= rv)
  370|  12.9k|            return false;
  371|  12.9k|          break;
  372|  12.9k|        case less_equal:
  373|  12.9k|          if(lv > rv)
  374|  12.9k|            return false;
  375|  12.9k|          break;
  376|  12.9k|        case greater_equal:
  377|  12.9k|          if(lv < rv)
  378|  12.9k|            return false;
  379|  12.9k|          break;
  380|  12.9k|      }
  381|  12.9k|      return true;
  382|  12.9k|    };
  383|       |
  384|  12.9k|    auto lhs_v = operands[0]->evaluate(env);
  385|   139k|    for(auto i = 0u; i != ops.size(); ++i)
  ------------------
  |  Branch (385:22): [True: 135k, False: 4.36k]
  ------------------
  386|   135k|    {
  387|   135k|      auto rhs_v = operands[i + 1]->evaluate(env);
  388|       |
  389|   135k|      if(lhs_v.empty())
  ------------------
  |  Branch (389:10): [True: 9, False: 135k]
  ------------------
  390|      9|      {
  391|      9|        throw RuntimeError(ErrorNotInit("left", opStr(ops[i])));
  392|      9|      }
  393|   135k|      if(rhs_v.empty())
  ------------------
  |  Branch (393:10): [True: 5, False: 135k]
  ------------------
  394|      5|      {
  395|      5|        throw RuntimeError(ErrorNotInit("right", opStr(ops[i])));
  396|      5|      }
  397|   135k|      const Any False(0.0);
  398|       |
  399|   135k|      if(lhs_v.isNumber() && rhs_v.isNumber())
  ------------------
  |  Branch (399:10): [True: 123k, False: 12.0k]
  |  Branch (399:30): [True: 120k, False: 3.50k]
  ------------------
  400|   120k|      {
  401|   120k|        auto lv = lhs_v.cast<double>();
  402|   120k|        auto rv = rhs_v.cast<double>();
  403|   120k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (403:12): [True: 1.25k, False: 118k]
  ------------------
  404|  1.25k|        {
  405|  1.25k|          return False;
  406|  1.25k|        }
  407|   120k|      }
  408|  15.5k|      else if(lhs_v.isString() && rhs_v.isString())
  ------------------
  |  Branch (408:15): [True: 11.4k, False: 4.03k]
  |  Branch (408:35): [True: 7.94k, False: 3.53k]
  ------------------
  409|  7.94k|      {
  410|  7.94k|        auto lv = lhs_v.cast<SimpleString>();
  411|  7.94k|        auto rv = rhs_v.cast<SimpleString>();
  412|  7.94k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (412:12): [True: 3.83k, False: 4.10k]
  ------------------
  413|  3.83k|        {
  414|  3.83k|          return False;
  415|  3.83k|        }
  416|  7.94k|      }
  417|  7.56k|      else if(lhs_v.isString() && rhs_v.isNumber())
  ------------------
  |  Branch (417:15): [True: 3.53k, False: 4.03k]
  |  Branch (417:35): [True: 3.53k, False: 0]
  ------------------
  418|  3.53k|      {
  419|  3.53k|        auto lv = StringToDouble(lhs_v, env);
  420|  3.53k|        auto rv = rhs_v.cast<double>();
  421|  3.53k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (421:12): [True: 1.44k, False: 2.09k]
  ------------------
  422|  1.44k|        {
  423|  1.44k|          return False;
  424|  1.44k|        }
  425|  3.53k|      }
  426|  4.03k|      else if(lhs_v.isNumber() && rhs_v.isString())
  ------------------
  |  Branch (426:15): [True: 3.50k, False: 532]
  |  Branch (426:35): [True: 3.50k, False: 0]
  ------------------
  427|  3.50k|      {
  428|  3.50k|        auto lv = lhs_v.cast<double>();
  429|  3.50k|        auto rv = StringToDouble(rhs_v, env);
  430|  3.50k|        if(!SwitchImpl(lv, rv, ops[i]))
  ------------------
  |  Branch (430:12): [True: 1.51k, False: 1.98k]
  ------------------
  431|  1.51k|        {
  432|  1.51k|          return False;
  433|  1.51k|        }
  434|  3.50k|      }
  435|    532|      else
  436|    532|      {
  437|    532|        throw RuntimeError(StrCat("Can't mix different types in Comparison. "
  438|    532|                                  "Left operand [",
  439|    532|                                  BT::demangle(lhs_v.type()), "] right operand [",
  440|    532|                                  BT::demangle(rhs_v.type()), "]"));
  441|    532|      }
  442|   126k|      lhs_v = rhs_v;
  443|   126k|    }
  444|  4.36k|    return Any(1.0);
  445|  12.9k|  }
_ZNK2BT3Ast14ExprComparison5opStrENS1_4op_tE:
  329|     14|  {
  330|     14|    switch(op)
  ------------------
  |  Branch (330:12): [True: 14, False: 0]
  ------------------
  331|     14|    {
  332|      1|      case equal:
  ------------------
  |  Branch (332:7): [True: 1, False: 13]
  ------------------
  333|      1|        return "==";
  334|      1|      case not_equal:
  ------------------
  |  Branch (334:7): [True: 1, False: 13]
  ------------------
  335|      1|        return "!=";
  336|      7|      case less:
  ------------------
  |  Branch (336:7): [True: 7, False: 7]
  ------------------
  337|      7|        return "<";
  338|      5|      case greater:
  ------------------
  |  Branch (338:7): [True: 5, False: 9]
  ------------------
  339|      5|        return ">";
  340|      0|      case less_equal:
  ------------------
  |  Branch (340:7): [True: 0, False: 14]
  ------------------
  341|      0|        return "<=";
  342|      0|      case greater_equal:
  ------------------
  |  Branch (342:7): [True: 0, False: 14]
  ------------------
  343|      0|        return ">=";
  344|     14|    }
  345|      0|    return "";
  346|     14|  }
_ZZNK2BT3Ast14ExprComparison8evaluateERNS0_11EnvironmentEENKUlRKT_RKT0_NS1_4op_tEE_clIddEEDaS6_S9_SA_:
  353|   126k|    auto SwitchImpl = [&](const auto& lv, const auto& rv, op_t op) {
  354|   126k|      switch(op)
  ------------------
  |  Branch (354:14): [True: 126k, False: 0]
  ------------------
  355|   126k|      {
  356|  2.14k|        case equal:
  ------------------
  |  Branch (356:9): [True: 2.14k, False: 124k]
  ------------------
  357|  2.14k|          if(!IsSame(lv, rv))
  ------------------
  |  Branch (357:14): [True: 718, False: 1.42k]
  ------------------
  358|    718|            return false;
  359|  1.42k|          break;
  360|  57.7k|        case not_equal:
  ------------------
  |  Branch (360:9): [True: 57.7k, False: 69.1k]
  ------------------
  361|  57.7k|          if(IsSame(lv, rv))
  ------------------
  |  Branch (361:14): [True: 589, False: 57.1k]
  ------------------
  362|    589|            return false;
  363|  57.1k|          break;
  364|  57.1k|        case less:
  ------------------
  |  Branch (364:9): [True: 4.32k, False: 122k]
  ------------------
  365|  4.32k|          if(lv >= rv)
  ------------------
  |  Branch (365:14): [True: 898, False: 3.42k]
  ------------------
  366|    898|            return false;
  367|  3.42k|          break;
  368|  60.1k|        case greater:
  ------------------
  |  Branch (368:9): [True: 60.1k, False: 66.8k]
  ------------------
  369|  60.1k|          if(lv <= rv)
  ------------------
  |  Branch (369:14): [True: 711, False: 59.3k]
  ------------------
  370|    711|            return false;
  371|  59.3k|          break;
  372|  59.3k|        case less_equal:
  ------------------
  |  Branch (372:9): [True: 1.33k, False: 125k]
  ------------------
  373|  1.33k|          if(lv > rv)
  ------------------
  |  Branch (373:14): [True: 690, False: 646]
  ------------------
  374|    690|            return false;
  375|    646|          break;
  376|  1.28k|        case greater_equal:
  ------------------
  |  Branch (376:9): [True: 1.28k, False: 125k]
  ------------------
  377|  1.28k|          if(lv < rv)
  ------------------
  |  Branch (377:14): [True: 605, False: 679]
  ------------------
  378|    605|            return false;
  379|    679|          break;
  380|   126k|      }
  381|   122k|      return true;
  382|   126k|    };
_ZN2BT3Ast6IsSameIdEEbRKT_S4_:
  304|  59.8k|{
  305|       |  if constexpr(std::is_same_v<double, T>)
  306|  59.8k|  {
  307|  59.8k|    constexpr double EPS = static_cast<double>(std::numeric_limits<float>::epsilon());
  308|  59.8k|    return std::abs(lv - rv) <= EPS;
  309|       |  }
  310|       |  else
  311|       |  {
  312|       |    return (lv == rv);
  313|       |  }
  314|  59.8k|}
_ZZNK2BT3Ast14ExprComparison8evaluateERNS0_11EnvironmentEENKUlRKT_RKT0_NS1_4op_tEE_clIN7SafeAny12SimpleStringESE_EEDaS6_S9_SA_:
  353|  7.94k|    auto SwitchImpl = [&](const auto& lv, const auto& rv, op_t op) {
  354|  7.94k|      switch(op)
  ------------------
  |  Branch (354:14): [True: 7.94k, False: 0]
  ------------------
  355|  7.94k|      {
  356|  1.07k|        case equal:
  ------------------
  |  Branch (356:9): [True: 1.07k, False: 6.86k]
  ------------------
  357|  1.07k|          if(!IsSame(lv, rv))
  ------------------
  |  Branch (357:14): [True: 548, False: 527]
  ------------------
  358|    548|            return false;
  359|    527|          break;
  360|    989|        case not_equal:
  ------------------
  |  Branch (360:9): [True: 989, False: 6.95k]
  ------------------
  361|    989|          if(IsSame(lv, rv))
  ------------------
  |  Branch (361:14): [True: 391, False: 598]
  ------------------
  362|    391|            return false;
  363|    598|          break;
  364|  1.56k|        case less:
  ------------------
  |  Branch (364:9): [True: 1.56k, False: 6.37k]
  ------------------
  365|  1.56k|          if(lv >= rv)
  ------------------
  |  Branch (365:14): [True: 996, False: 573]
  ------------------
  366|    996|            return false;
  367|    573|          break;
  368|  1.47k|        case greater:
  ------------------
  |  Branch (368:9): [True: 1.47k, False: 6.46k]
  ------------------
  369|  1.47k|          if(lv <= rv)
  ------------------
  |  Branch (369:14): [True: 793, False: 685]
  ------------------
  370|    793|            return false;
  371|    685|          break;
  372|  1.35k|        case less_equal:
  ------------------
  |  Branch (372:9): [True: 1.35k, False: 6.58k]
  ------------------
  373|  1.35k|          if(lv > rv)
  ------------------
  |  Branch (373:14): [True: 530, False: 827]
  ------------------
  374|    530|            return false;
  375|    827|          break;
  376|  1.47k|        case greater_equal:
  ------------------
  |  Branch (376:9): [True: 1.47k, False: 6.46k]
  ------------------
  377|  1.47k|          if(lv < rv)
  ------------------
  |  Branch (377:14): [True: 581, False: 894]
  ------------------
  378|    581|            return false;
  379|    894|          break;
  380|  7.94k|      }
  381|  4.10k|      return true;
  382|  7.94k|    };
_ZN2BT3Ast6IsSameIN7SafeAny12SimpleStringEEEbRKT_S6_:
  304|  2.06k|{
  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.06k|  {
  312|  2.06k|    return (lv == rv);
  313|  2.06k|  }
  314|  2.06k|}
_ZN2BT3Ast20ExprBinaryArithmeticC2ESt10shared_ptrINS0_8ExprBaseEENS1_4op_tES4_:
  199|  86.5k|    : op(op), lhs(std::move(lhs)), rhs(std::move(rhs))
  200|  86.5k|  {}
_ZNK2BT3Ast20ExprBinaryArithmetic8evaluateERNS0_11EnvironmentE:
  203|  14.0k|  {
  204|  14.0k|    auto lhs_v = lhs->evaluate(env);
  205|  14.0k|    auto rhs_v = rhs->evaluate(env);
  206|       |
  207|  14.0k|    if(lhs_v.empty())
  ------------------
  |  Branch (207:8): [True: 12, False: 14.0k]
  ------------------
  208|     12|    {
  209|     12|      throw RuntimeError(ErrorNotInit("left", opStr()));
  210|     12|    }
  211|  14.0k|    if(rhs_v.empty())
  ------------------
  |  Branch (211:8): [True: 3, False: 14.0k]
  ------------------
  212|      3|    {
  213|      3|      throw RuntimeError(ErrorNotInit("right", opStr()));
  214|      3|    }
  215|       |
  216|  14.0k|    if(rhs_v.isNumber() && lhs_v.isNumber())
  ------------------
  |  Branch (216:8): [True: 6.33k, False: 7.73k]
  |  Branch (216:28): [True: 4.42k, False: 1.90k]
  ------------------
  217|  4.42k|    {
  218|  4.42k|      auto lv = lhs_v.cast<double>();
  219|  4.42k|      auto rv = rhs_v.cast<double>();
  220|       |
  221|  4.42k|      switch(op)
  222|  4.42k|      {
  223|    445|        case plus:
  ------------------
  |  Branch (223:9): [True: 445, False: 3.98k]
  ------------------
  224|    445|          return Any(lv + rv);
  225|    579|        case minus:
  ------------------
  |  Branch (225:9): [True: 579, False: 3.84k]
  ------------------
  226|    579|          return Any(lv - rv);
  227|    301|        case times:
  ------------------
  |  Branch (227:9): [True: 301, False: 4.12k]
  ------------------
  228|    301|          return Any(lv * rv);
  229|    435|        case div:
  ------------------
  |  Branch (229:9): [True: 435, False: 3.99k]
  ------------------
  230|    435|          return Any(lv / rv);
  231|  2.66k|        default: {
  ------------------
  |  Branch (231:9): [True: 2.66k, False: 1.76k]
  ------------------
  232|  2.66k|        }
  233|  4.42k|      }
  234|       |
  235|  2.66k|      if(op == bit_and || op == bit_or || op == bit_xor)
  ------------------
  |  Branch (235:10): [True: 415, False: 2.25k]
  |  Branch (235:27): [True: 484, False: 1.76k]
  |  Branch (235:43): [True: 204, False: 1.56k]
  ------------------
  236|  1.10k|      {
  237|  1.10k|        try
  238|  1.10k|        {
  239|  1.10k|          int64_t li = lhs_v.cast<int64_t>();
  240|  1.10k|          int64_t ri = rhs_v.cast<int64_t>();
  241|  1.10k|          switch(op)
  242|  1.10k|          {
  243|    410|            case bit_and:
  ------------------
  |  Branch (243:13): [True: 410, False: 693]
  ------------------
  244|    410|              return Any(static_cast<double>(li & ri));
  245|    481|            case bit_or:
  ------------------
  |  Branch (245:13): [True: 481, False: 622]
  ------------------
  246|    481|              return Any(static_cast<double>(li | ri));
  247|    203|            case bit_xor:
  ------------------
  |  Branch (247:13): [True: 203, False: 900]
  ------------------
  248|    203|              return Any(static_cast<double>(li ^ ri));
  249|      0|            default: {
  ------------------
  |  Branch (249:13): [True: 0, False: 1.10k]
  ------------------
  250|      0|            }
  251|  1.10k|          }
  252|  1.10k|        }
  253|  1.10k|        catch(...)
  254|  1.10k|        {
  255|      9|          throw RuntimeError("Binary operators are not allowed if "
  256|      9|                             "one of the operands is not an integer");
  257|      9|        }
  258|  1.10k|      }
  259|       |
  260|  1.56k|      if(op == logic_or || op == logic_and)
  ------------------
  |  Branch (260:10): [True: 644, False: 918]
  |  Branch (260:28): [True: 697, False: 221]
  ------------------
  261|  1.34k|      {
  262|  1.34k|        try
  263|  1.34k|        {
  264|  1.34k|          auto lb = lhs_v.cast<bool>();
  265|  1.34k|          auto rb = rhs_v.cast<bool>();
  266|  1.34k|          switch(op)
  267|  1.34k|          {
  268|    595|            case logic_or:
  ------------------
  |  Branch (268:13): [True: 595, False: 746]
  ------------------
  269|    595|              return Any(static_cast<double>(lb || rb));
  ------------------
  |  Branch (269:46): [True: 214, False: 381]
  |  Branch (269:52): [True: 5, False: 376]
  ------------------
  270|    607|            case logic_and:
  ------------------
  |  Branch (270:13): [True: 607, False: 734]
  ------------------
  271|    607|              return Any(static_cast<double>(lb && rb));
  ------------------
  |  Branch (271:46): [True: 329, False: 278]
  |  Branch (271:52): [True: 323, False: 6]
  ------------------
  272|      0|            default: {
  ------------------
  |  Branch (272:13): [True: 0, False: 1.34k]
  ------------------
  273|      0|            }
  274|  1.34k|          }
  275|  1.34k|        }
  276|  1.34k|        catch(...)
  277|  1.34k|        {
  278|    139|          throw RuntimeError("Logic operators are not allowed if "
  279|    139|                             "one of the operands is not castable to bool");
  280|    139|        }
  281|  1.34k|      }
  282|  1.56k|    }
  283|  9.63k|    else if(rhs_v.isString() && lhs_v.isString() && op == plus)
  ------------------
  |  Branch (283:13): [True: 7.43k, False: 2.19k]
  |  Branch (283:33): [True: 5.91k, False: 1.52k]
  |  Branch (283:53): [True: 5.51k, False: 400]
  ------------------
  284|  5.51k|    {
  285|  5.51k|      return Any(lhs_v.cast<std::string>() + rhs_v.cast<std::string>());
  286|  5.51k|    }
  287|  4.12k|    else if(op == concat && ((rhs_v.isString() && lhs_v.isString()) ||
  ------------------
  |  Branch (287:13): [True: 3.80k, False: 320]
  |  Branch (287:31): [True: 1.90k, False: 1.89k]
  |  Branch (287:51): [True: 393, False: 1.51k]
  ------------------
  288|  3.40k|                             (rhs_v.isString() && lhs_v.isNumber()) ||
  ------------------
  |  Branch (288:31): [True: 1.51k, False: 1.89k]
  |  Branch (288:51): [True: 1.51k, False: 0]
  ------------------
  289|  1.89k|                             (rhs_v.isNumber() && lhs_v.isString())))
  ------------------
  |  Branch (289:31): [True: 1.89k, False: 0]
  |  Branch (289:51): [True: 1.89k, False: 0]
  ------------------
  290|  3.80k|    {
  291|  3.80k|      return Any(lhs_v.cast<std::string>() + rhs_v.cast<std::string>());
  292|  3.80k|    }
  293|    320|    else
  294|    320|    {
  295|    320|      throw RuntimeError("Operation not permitted");
  296|    320|    }
  297|       |
  298|    221|    return {};  // unreachable
  299|  14.0k|  }
_ZNK2BT3Ast20ExprBinaryArithmetic5opStrEv:
  169|     15|  {
  170|     15|    switch(op)
  ------------------
  |  Branch (170:12): [True: 15, False: 0]
  ------------------
  171|     15|    {
  172|      2|      case plus:
  ------------------
  |  Branch (172:7): [True: 2, False: 13]
  ------------------
  173|      2|        return "+";
  174|      1|      case minus:
  ------------------
  |  Branch (174:7): [True: 1, False: 14]
  ------------------
  175|      1|        return "-";
  176|      2|      case times:
  ------------------
  |  Branch (176:7): [True: 2, False: 13]
  ------------------
  177|      2|        return "*";
  178|      2|      case div:
  ------------------
  |  Branch (178:7): [True: 2, False: 13]
  ------------------
  179|      2|        return "/";
  180|      0|      case concat:
  ------------------
  |  Branch (180:7): [True: 0, False: 15]
  ------------------
  181|      0|        return "..";
  182|      5|      case bit_and:
  ------------------
  |  Branch (182:7): [True: 5, False: 10]
  ------------------
  183|      5|        return "&";
  184|      1|      case bit_or:
  ------------------
  |  Branch (184:7): [True: 1, False: 14]
  ------------------
  185|      1|        return "|";
  186|      1|      case bit_xor:
  ------------------
  |  Branch (186:7): [True: 1, False: 14]
  ------------------
  187|      1|        return "^";
  188|      0|      case logic_and:
  ------------------
  |  Branch (188:7): [True: 0, False: 15]
  ------------------
  189|      0|        return "&&";
  190|      1|      case logic_or:
  ------------------
  |  Branch (190:7): [True: 1, False: 14]
  ------------------
  191|      1|        return "||";
  192|     15|    }
  193|      0|    return "";
  194|     15|  }

_ZN7SafeAny7details13convertNumberIldEEvRKT_RT0_:
  145|   253k|{
  146|   253k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  147|   253k|                                                                          "convertible");
  148|       |
  149|   253k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (149:34): [True: 0, Folded]
  |  Branch (149:55): [Folded, False: 0]
  ------------------
  150|       |
  151|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  152|       |  {
  153|       |    if(source < 0)
  154|       |    {
  155|       |      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  156|       |    }
  157|       |  }
  158|       |  // these conversions are always safe (no check needed):
  159|       |  // - same type
  160|       |  // - float -> double
  161|       |  // - floating point to bool (C-style: any non-zero is true)
  162|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  163|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  164|       |  {
  165|       |    target = static_cast<DST>(source);
  166|       |  }
  167|       |  // integer to bool: only 0 and 1 are valid
  168|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  169|       |  {
  170|       |    checkLowerLimit<SRC, DST>(source);
  171|       |    target = static_cast<DST>(source);
  172|       |  }
  173|       |  else if constexpr(both_integers)
  174|       |  {
  175|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  176|       |    {
  177|       |      checkUpperLimit<SRC, DST>(source);
  178|       |    }
  179|       |    // casting to a smaller number need to be check
  180|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  181|       |    {
  182|       |      if constexpr(is_signed<SRC>())
  183|       |      {
  184|       |        checkLowerLimit<SRC, DST>(source);
  185|       |      }
  186|       |      checkUpperLimit<SRC, DST>(source);
  187|       |    }
  188|       |    target = static_cast<DST>(source);
  189|       |  }
  190|       |  // casting to/from floating points might cause truncation.
  191|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  192|       |                    std::is_floating_point<DST>::value)
  193|   253k|  {
  194|   253k|    bool both_float =
  195|   253k|        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  ------------------
  |  Branch (195:9): [Folded, False: 253k]
  |  Branch (195:47): [True: 0, Folded]
  ------------------
  196|       |    // to avoid being too pedantic, let's accept casting between double and float
  197|   253k|    if(!both_float)
  ------------------
  |  Branch (197:8): [True: 253k, False: 0]
  ------------------
  198|   253k|    {
  199|   253k|      checkTruncation<SRC, DST>(source);
  200|   253k|    }
  201|   253k|    target = static_cast<DST>(source);
  202|   253k|  }
  203|   253k|}
_ZN7SafeAny7details15checkTruncationIldEEvRKT_:
   92|   253k|{
   93|       |  // Handle integer to floating point
   94|       |  if constexpr(std::is_integral_v<From> && std::is_floating_point_v<To>)
   95|   253k|  {
   96|       |    // Check if value can be represented exactly in the target type
   97|   253k|    constexpr uint64_t max_exact = (1LL << std::numeric_limits<double>::digits) - 1;
   98|   253k|    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|   253k|    {
  105|   253k|      doesnt_fit = std::abs(static_cast<int64_t>(from)) > static_cast<int64_t>(max_exact);
  106|   253k|    }
  107|   253k|    if(doesnt_fit)
  ------------------
  |  Branch (107:8): [True: 22, False: 253k]
  ------------------
  108|     22|    {
  109|     22|      throw std::runtime_error("Loss of precision when converting a large integer number "
  110|     22|                               "to floating point:" +
  111|     22|                               std::to_string(from));
  112|     22|    }
  113|       |  }
  114|       |  // Handle floating point to integer
  115|       |  else if constexpr(std::is_floating_point_v<From> && std::is_integral_v<To>)
  116|       |  {
  117|       |    if(from > static_cast<From>(std::numeric_limits<To>::max()) ||
  118|       |       from < static_cast<From>(std::numeric_limits<To>::lowest()) ||
  119|       |       from != std::nearbyint(from))
  120|       |    {
  121|       |      throw std::runtime_error("Invalid floating point to integer conversion");
  122|       |    }
  123|       |  }
  124|       |  // Handle other conversions
  125|       |  else
  126|       |  {
  127|       |    if(from > static_cast<From>(std::numeric_limits<To>::max()) ||
  128|       |       from < static_cast<From>(std::numeric_limits<To>::lowest()))
  129|       |    {
  130|       |      throw std::runtime_error("Value outside numeric limits");
  131|       |    }
  132|       |    To as_target = static_cast<To>(from);
  133|       |    From back_to_source = static_cast<From>(as_target);
  134|       |    if(from != back_to_source)
  135|       |    {
  136|       |      throw std::runtime_error("Value truncated in conversion");
  137|       |    }
  138|       |  }
  139|   253k|}
_ZN7SafeAny7details13convertNumberIdlEEvRKT_RT0_:
  145|  2.15k|{
  146|  2.15k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  147|  2.15k|                                                                          "convertible");
  148|       |
  149|  2.15k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (149:34): [Folded, False: 2.15k]
  |  Branch (149:55): [True: 0, Folded]
  ------------------
  150|       |
  151|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  152|       |  {
  153|       |    if(source < 0)
  154|       |    {
  155|       |      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  156|       |    }
  157|       |  }
  158|       |  // these conversions are always safe (no check needed):
  159|       |  // - same type
  160|       |  // - float -> double
  161|       |  // - floating point to bool (C-style: any non-zero is true)
  162|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  163|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  164|       |  {
  165|       |    target = static_cast<DST>(source);
  166|       |  }
  167|       |  // integer to bool: only 0 and 1 are valid
  168|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  169|       |  {
  170|       |    checkLowerLimit<SRC, DST>(source);
  171|       |    target = static_cast<DST>(source);
  172|       |  }
  173|       |  else if constexpr(both_integers)
  174|       |  {
  175|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  176|       |    {
  177|       |      checkUpperLimit<SRC, DST>(source);
  178|       |    }
  179|       |    // casting to a smaller number need to be check
  180|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  181|       |    {
  182|       |      if constexpr(is_signed<SRC>())
  183|       |      {
  184|       |        checkLowerLimit<SRC, DST>(source);
  185|       |      }
  186|       |      checkUpperLimit<SRC, DST>(source);
  187|       |    }
  188|       |    target = static_cast<DST>(source);
  189|       |  }
  190|       |  // casting to/from floating points might cause truncation.
  191|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  192|       |                    std::is_floating_point<DST>::value)
  193|  2.15k|  {
  194|  2.15k|    bool both_float =
  195|  2.15k|        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  ------------------
  |  Branch (195:9): [True: 2.15k, Folded]
  |  Branch (195:47): [Folded, False: 2.15k]
  ------------------
  196|       |    // to avoid being too pedantic, let's accept casting between double and float
  197|  2.15k|    if(!both_float)
  ------------------
  |  Branch (197:8): [True: 2.15k, False: 0]
  ------------------
  198|  2.15k|    {
  199|  2.15k|      checkTruncation<SRC, DST>(source);
  200|  2.15k|    }
  201|  2.15k|    target = static_cast<DST>(source);
  202|  2.15k|  }
  203|  2.15k|}
_ZN7SafeAny7details15checkTruncationIdlEEvRKT_:
   92|  2.15k|{
   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|  2.15k|  {
  117|  2.15k|    if(from > static_cast<From>(std::numeric_limits<To>::max()) ||
  ------------------
  |  Branch (117:8): [True: 1, False: 2.15k]
  ------------------
  118|  2.15k|       from < static_cast<From>(std::numeric_limits<To>::lowest()) ||
  ------------------
  |  Branch (118:8): [True: 3, False: 2.15k]
  ------------------
  119|  2.15k|       from != std::nearbyint(from))
  ------------------
  |  Branch (119:8): [True: 9, False: 2.14k]
  ------------------
  120|     13|    {
  121|     13|      throw std::runtime_error("Invalid floating point to integer conversion");
  122|     13|    }
  123|       |  }
  124|       |  // Handle other conversions
  125|       |  else
  126|       |  {
  127|       |    if(from > static_cast<From>(std::numeric_limits<To>::max()) ||
  128|       |       from < static_cast<From>(std::numeric_limits<To>::lowest()))
  129|       |    {
  130|       |      throw std::runtime_error("Value outside numeric limits");
  131|       |    }
  132|       |    To as_target = static_cast<To>(from);
  133|       |    From back_to_source = static_cast<From>(as_target);
  134|       |    if(from != back_to_source)
  135|       |    {
  136|       |      throw std::runtime_error("Value truncated in conversion");
  137|       |    }
  138|       |  }
  139|  2.15k|}
_ZN7SafeAny7details13convertNumberIlbEEvRKT_RT0_:
  145|  1.56k|{
  146|  1.56k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  147|  1.56k|                                                                          "convertible");
  148|       |
  149|  1.56k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (149:34): [True: 0, Folded]
  |  Branch (149:55): [True: 0, Folded]
  ------------------
  150|       |
  151|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  152|  1.56k|  {
  153|  1.56k|    if(source < 0)
  ------------------
  |  Branch (153:8): [True: 57, False: 1.50k]
  ------------------
  154|     57|    {
  155|     57|      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  156|     57|    }
  157|  1.56k|  }
  158|       |  // these conversions are always safe (no check needed):
  159|       |  // - same type
  160|       |  // - float -> double
  161|       |  // - floating point to bool (C-style: any non-zero is true)
  162|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  163|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  164|       |  {
  165|       |    target = static_cast<DST>(source);
  166|       |  }
  167|       |  // integer to bool: only 0 and 1 are valid
  168|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  169|  1.56k|  {
  170|  1.56k|    checkLowerLimit<SRC, DST>(source);
  171|  1.56k|    target = static_cast<DST>(source);
  172|       |  }
  173|       |  else if constexpr(both_integers)
  174|       |  {
  175|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  176|       |    {
  177|       |      checkUpperLimit<SRC, DST>(source);
  178|       |    }
  179|       |    // casting to a smaller number need to be check
  180|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  181|       |    {
  182|       |      if constexpr(is_signed<SRC>())
  183|       |      {
  184|       |        checkLowerLimit<SRC, DST>(source);
  185|       |      }
  186|       |      checkUpperLimit<SRC, DST>(source);
  187|       |    }
  188|       |    target = static_cast<DST>(source);
  189|       |  }
  190|       |  // casting to/from floating points might cause truncation.
  191|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  192|       |                    std::is_floating_point<DST>::value)
  193|       |  {
  194|       |    bool both_float =
  195|       |        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  196|       |    // to avoid being too pedantic, let's accept casting between double and float
  197|       |    if(!both_float)
  198|       |    {
  199|       |      checkTruncation<SRC, DST>(source);
  200|       |    }
  201|       |    target = static_cast<DST>(source);
  202|       |  }
  203|  1.56k|}
_ZN7SafeAny7details15checkLowerLimitIlbEEvRKT_:
   76|  1.50k|{
   77|       |  if constexpr(std::is_same<To, bool>::value)
   78|  1.50k|  {
   79|  1.50k|    if(from != 0 && from != 1)
  ------------------
  |  Branch (79:8): [True: 752, False: 752]
  |  Branch (79:21): [True: 81, False: 671]
  ------------------
   80|     81|    {
   81|     81|      throw std::runtime_error("Implicit casting to bool is not allowed");
   82|     81|    }
   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.50k|}
_ZN7SafeAny7details13convertNumberIdbEEvRKT_RT0_:
  145|  1.03k|{
  146|  1.03k|  static_assert(is_convertible_type<SRC>() && is_convertible_type<DST>(), "Not "
  147|  1.03k|                                                                          "convertible");
  148|       |
  149|  1.03k|  constexpr bool both_integers = is_integer<SRC>() && is_integer<DST>();
  ------------------
  |  Branch (149:34): [Folded, False: 1.03k]
  |  Branch (149:55): [True: 0, Folded]
  ------------------
  150|       |
  151|       |  if constexpr(is_signed<SRC>() && !is_signed<DST>())
  152|  1.03k|  {
  153|  1.03k|    if(source < 0)
  ------------------
  |  Branch (153:8): [True: 1, False: 1.03k]
  ------------------
  154|      1|    {
  155|      1|      throw std::runtime_error("Value is negative and can't be converted to unsigned");
  156|      1|    }
  157|  1.03k|  }
  158|       |  // these conversions are always safe (no check needed):
  159|       |  // - same type
  160|       |  // - float -> double
  161|       |  // - floating point to bool (C-style: any non-zero is true)
  162|       |  if constexpr(is_same<SRC, DST>() || (is_same<SRC, float>() && is_same<DST, double>()) ||
  163|       |               (std::is_floating_point<SRC>::value && is_same<DST, bool>()))
  164|  1.03k|  {
  165|  1.03k|    target = static_cast<DST>(source);
  166|       |  }
  167|       |  // integer to bool: only 0 and 1 are valid
  168|       |  else if constexpr(is_integer<SRC>() && is_same<DST, bool>())
  169|       |  {
  170|       |    checkLowerLimit<SRC, DST>(source);
  171|       |    target = static_cast<DST>(source);
  172|       |  }
  173|       |  else if constexpr(both_integers)
  174|       |  {
  175|       |    if constexpr(sizeof(SRC) == sizeof(DST) && !is_signed<SRC>() && is_signed<DST>())
  176|       |    {
  177|       |      checkUpperLimit<SRC, DST>(source);
  178|       |    }
  179|       |    // casting to a smaller number need to be check
  180|       |    else if constexpr(sizeof(SRC) > sizeof(DST))
  181|       |    {
  182|       |      if constexpr(is_signed<SRC>())
  183|       |      {
  184|       |        checkLowerLimit<SRC, DST>(source);
  185|       |      }
  186|       |      checkUpperLimit<SRC, DST>(source);
  187|       |    }
  188|       |    target = static_cast<DST>(source);
  189|       |  }
  190|       |  // casting to/from floating points might cause truncation.
  191|       |  else if constexpr(std::is_floating_point<SRC>::value ||
  192|       |                    std::is_floating_point<DST>::value)
  193|       |  {
  194|       |    bool both_float =
  195|       |        std::is_floating_point<SRC>::value && std::is_floating_point<DST>::value;
  196|       |    // to avoid being too pedantic, let's accept casting between double and float
  197|       |    if(!both_float)
  198|       |    {
  199|       |      checkTruncation<SRC, DST>(source);
  200|       |    }
  201|       |    target = static_cast<DST>(source);
  202|       |  }
  203|  1.03k|}

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

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

_ZNK2BT3Any8isNumberEv:
  346|   305k|{
  347|   305k|  return _any.type() == typeid(int64_t) || _any.type() == typeid(uint64_t) ||
  ------------------
  |  Branch (347:10): [True: 258k, False: 47.0k]
  |  Branch (347:44): [True: 0, False: 47.0k]
  ------------------
  348|  47.0k|         _any.type() == typeid(double);
  ------------------
  |  Branch (348:10): [True: 16.3k, False: 30.7k]
  ------------------
  349|   305k|}
_ZN2BT3AnyC2Ev:
   78|  63.3k|  Any() : _original_type(UndefinedAnyType)
   79|  63.3k|  {}
_ZN2BT3AnyD2Ev:
   81|  5.04M|  ~Any() = default;
_ZNK2BT3Any4castIdEET_v:
  169|   271k|  {
  170|   271k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 271k, False: 207]
  ------------------
  171|   271k|    {
  172|   271k|      return res.value();
  173|   271k|    }
  174|    207|    else
  175|    207|    {
  176|    207|      throw std::runtime_error(res.error());
  177|    207|    }
  178|   271k|  }
_ZNK2BT3Any7tryCastIdEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  514|   271k|{
  515|   271k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  516|   271k|                                              "can not cast to reference");
  517|       |
  518|   271k|  if(_any.empty())
  ------------------
  |  Branch (518:6): [True: 2, False: 271k]
  ------------------
  519|      2|  {
  520|      2|    throw std::runtime_error("Any::cast failed because it is empty");
  521|      2|  }
  522|       |
  523|   271k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (523:6): [True: 10.7k, False: 260k]
  ------------------
  524|  10.7k|  {
  525|  10.7k|    return linb::any_cast<T>(_any);
  526|  10.7k|  }
  527|       |
  528|       |  // special case when the output is an enum.
  529|       |  // We will try first a int conversion
  530|       |  if constexpr(std::is_enum_v<T>)
  531|       |  {
  532|       |    if(isNumber())
  533|       |    {
  534|       |      return static_cast<T>(convert<int>().value());
  535|       |    }
  536|       |    if(isString())
  537|       |    {
  538|       |      if(auto out = stringToNumber<int64_t>())
  539|       |      {
  540|       |        return static_cast<T>(out.value());
  541|       |      }
  542|       |    }
  543|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  544|       |  }
  545|       |
  546|   260k|  if(isString())
  ------------------
  |  Branch (546:6): [True: 7.31k, False: 253k]
  ------------------
  547|  7.31k|  {
  548|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  549|  7.31k|    {
  550|  7.31k|      if(auto out = stringToNumber<T>())
  ------------------
  |  Branch (550:15): [True: 7.13k, False: 183]
  ------------------
  551|  7.13k|      {
  552|  7.13k|        return out.value();
  553|  7.13k|      }
  554|    183|      else
  555|    183|      {
  556|    183|        return out;
  557|    183|      }
  558|  7.31k|    }
  559|  7.31k|  }
  560|       |
  561|   260k|  if(auto res = convert<T>())
  ------------------
  |  Branch (561:11): [True: 253k, False: 7.34k]
  ------------------
  562|   253k|  {
  563|   253k|    return std::move(res.value());
  564|   253k|  }
  565|  7.34k|  else
  566|  7.34k|  {
  567|  7.34k|    return res;
  568|  7.34k|  }
  569|   260k|}
_ZNK2BT3Any10castedTypeEv:
  200|   352k|  {
  201|   352k|    return _any.type();
  202|   352k|  }
_ZNK2BT3Any8isStringEv:
  141|   381k|  {
  142|   381k|    return _any.type() == typeid(SafeAny::SimpleString);
  143|   381k|  }
_ZNK2BT3Any14stringToNumberIdEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  422|  7.31k|{
  423|  7.31k|  static_assert(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, "Expecting a "
  424|  7.31k|                                                                     "numeric type");
  425|       |
  426|  7.31k|  const auto str = linb::any_cast<SafeAny::SimpleString>(_any);
  427|       |#if __cpp_lib_to_chars >= 201611L
  428|       |  T out;
  429|       |  auto [ptr, err] = std::from_chars(str.data(), str.data() + str.size(), out);
  430|       |  if(err == std::errc())
  431|       |  {
  432|       |    return out;
  433|       |  }
  434|       |  else
  435|       |  {
  436|       |    return nonstd::make_unexpected("Any failed string to number conversion");
  437|       |  }
  438|       |#else
  439|  7.31k|  try
  440|  7.31k|  {
  441|       |    if constexpr(std::is_same_v<T, uint16_t>)
  442|       |    {
  443|       |      return std::stoul(str.toStdString());
  444|       |    }
  445|       |    if constexpr(std::is_integral_v<T>)
  446|       |    {
  447|       |      const int64_t val = std::stol(str.toStdString());
  448|       |      Any temp_any(val);
  449|       |      return temp_any.convert<T>();
  450|       |    }
  451|       |    if constexpr(std::is_floating_point_v<T>)
  452|  7.31k|    {
  453|  7.31k|      return std::stod(str.toStdString());
  454|  7.31k|    }
  455|  7.31k|  }
  456|  7.31k|  catch(...)
  457|  7.31k|  {
  458|    183|    return nonstd::make_unexpected("Any failed string to number conversion");
  459|    183|  }
  460|      0|#endif
  461|      0|  return nonstd::make_unexpected("Any conversion from string failed");
  462|  7.31k|}
_ZNK2BT3Any7convertIdEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEPNSt9enable_ifIXsr3std13is_arithmeticIS5_EE5valueEvE4typeE:
  487|   253k|{
  488|   253k|  using SafeAny::details::convertNumber;
  489|   253k|  DST out;
  490|       |
  491|   253k|  const auto& type = _any.type();
  492|       |
  493|   253k|  if(type == typeid(int64_t))
  ------------------
  |  Branch (493:6): [True: 253k, False: 0]
  ------------------
  494|   253k|  {
  495|   253k|    convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
  496|   253k|  }
  497|      0|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (497:11): [True: 0, False: 0]
  ------------------
  498|      0|  {
  499|      0|    convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
  500|      0|  }
  501|      0|  else if(type == typeid(double))
  ------------------
  |  Branch (501:11): [True: 0, False: 0]
  ------------------
  502|      0|  {
  503|      0|    convertNumber<double, DST>(linb::any_cast<double>(_any), out);
  504|      0|  }
  505|      0|  else
  506|      0|  {
  507|      0|    return nonstd::make_unexpected(errorMsg<DST>());
  508|      0|  }
  509|   253k|  return out;
  510|   253k|}
_ZNK2BT3Any4typeEv:
  194|  16.6k|  {
  195|  16.6k|    return _original_type;
  196|  16.6k|  }
_ZN2BT3AnyC2IiEERKT_PNSt9enable_ifIXoosr3std11is_integralIS2_EE5valuesr3std7is_enumIS2_EE5valueEvE4typeE:
  118|  5.48k|    : _any(int64_t(value)), _original_type(typeid(T))
  119|  5.48k|  {}
_ZN2BT3AnyaSERKS0_:
  329|   157k|{
  330|   157k|  if(this != &other)
  ------------------
  |  Branch (330:6): [True: 157k, False: 0]
  ------------------
  331|   157k|  {
  332|   157k|    this->_any = other._any;
  333|   157k|    this->_original_type = other._original_type;
  334|   157k|  }
  335|   157k|  return *this;
  336|   157k|}
_ZN2BT3AnyaSEOS0_:
  339|  40.2k|{
  340|  40.2k|  this->_any = std::move(other._any);
  341|  40.2k|  this->_original_type = other._original_type;
  342|  40.2k|  return *this;
  343|  40.2k|}
_ZNK2BT3Any8copyIntoERS0_:
  357|  9.99k|{
  358|  9.99k|  if(dst.empty())
  ------------------
  |  Branch (358:6): [True: 0, False: 9.99k]
  ------------------
  359|      0|  {
  360|      0|    dst = *this;
  361|      0|    return;
  362|      0|  }
  363|       |
  364|  9.99k|  const auto& dst_type = dst.castedType();
  365|       |
  366|  9.99k|  if((castedType() == dst_type) || (isString() && dst.isString()))
  ------------------
  |  Branch (366:6): [True: 8.87k, False: 1.12k]
  |  Branch (366:37): [True: 8, False: 1.11k]
  |  Branch (366:51): [True: 0, False: 8]
  ------------------
  367|  8.87k|  {
  368|  8.87k|    dst._any = _any;
  369|  8.87k|  }
  370|  1.12k|  else if(isNumber() && dst.isNumber())
  ------------------
  |  Branch (370:11): [True: 1.11k, False: 8]
  |  Branch (370:25): [True: 1.06k, False: 51]
  ------------------
  371|  1.06k|  {
  372|  1.06k|    if(dst_type == typeid(int64_t))
  ------------------
  |  Branch (372:8): [True: 860, False: 201]
  ------------------
  373|    860|    {
  374|    860|      dst._any = cast<int64_t>();
  375|    860|    }
  376|    201|    else if(dst_type == typeid(uint64_t))
  ------------------
  |  Branch (376:13): [True: 0, False: 201]
  ------------------
  377|      0|    {
  378|      0|      dst._any = cast<uint64_t>();
  379|      0|    }
  380|    201|    else if(dst_type == typeid(double))
  ------------------
  |  Branch (380:13): [True: 201, False: 0]
  ------------------
  381|    201|    {
  382|    201|      dst._any = cast<double>();
  383|    201|    }
  384|      0|    else
  385|      0|    {
  386|      0|      throw std::runtime_error("Any::copyInto fails");
  387|      0|    }
  388|  1.06k|  }
  389|     59|  else
  390|     59|  {
  391|     59|    throw std::runtime_error("Any::copyInto fails");
  392|     59|  }
  393|  9.99k|}
_ZNK2BT3Any5emptyEv:
  205|   346k|  {
  206|   346k|    return _any.empty();
  207|   346k|  }
_ZNK2BT3Any4castIlEET_v:
  169|  3.06k|  {
  170|  3.06k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 3.05k, False: 13]
  ------------------
  171|  3.05k|    {
  172|  3.05k|      return res.value();
  173|  3.05k|    }
  174|     13|    else
  175|     13|    {
  176|     13|      throw std::runtime_error(res.error());
  177|     13|    }
  178|  3.06k|  }
_ZNK2BT3Any7tryCastIlEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  514|  3.06k|{
  515|  3.06k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  516|  3.06k|                                              "can not cast to reference");
  517|       |
  518|  3.06k|  if(_any.empty())
  ------------------
  |  Branch (518:6): [True: 0, False: 3.06k]
  ------------------
  519|      0|  {
  520|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  521|      0|  }
  522|       |
  523|  3.06k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (523:6): [True: 907, False: 2.15k]
  ------------------
  524|    907|  {
  525|    907|    return linb::any_cast<T>(_any);
  526|    907|  }
  527|       |
  528|       |  // special case when the output is an enum.
  529|       |  // We will try first a int conversion
  530|       |  if constexpr(std::is_enum_v<T>)
  531|       |  {
  532|       |    if(isNumber())
  533|       |    {
  534|       |      return static_cast<T>(convert<int>().value());
  535|       |    }
  536|       |    if(isString())
  537|       |    {
  538|       |      if(auto out = stringToNumber<int64_t>())
  539|       |      {
  540|       |        return static_cast<T>(out.value());
  541|       |      }
  542|       |    }
  543|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  544|       |  }
  545|       |
  546|  2.15k|  if(isString())
  ------------------
  |  Branch (546:6): [True: 0, False: 2.15k]
  ------------------
  547|      0|  {
  548|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  549|      0|    {
  550|      0|      if(auto out = stringToNumber<T>())
  ------------------
  |  Branch (550:15): [True: 0, False: 0]
  ------------------
  551|      0|      {
  552|      0|        return out.value();
  553|      0|      }
  554|      0|      else
  555|      0|      {
  556|      0|        return out;
  557|      0|      }
  558|      0|    }
  559|      0|  }
  560|       |
  561|  2.15k|  if(auto res = convert<T>())
  ------------------
  |  Branch (561:11): [True: 2.14k, False: 13]
  ------------------
  562|  2.14k|  {
  563|  2.14k|    return std::move(res.value());
  564|  2.14k|  }
  565|     13|  else
  566|     13|  {
  567|     13|    return res;
  568|     13|  }
  569|  2.15k|}
_ZN2BT3AnyC2IlEERKT_PNSt9enable_ifIXoosr3std11is_integralIS2_EE5valuesr3std7is_enumIS2_EE5valueEvE4typeE:
  118|  1.36M|    : _any(int64_t(value)), _original_type(typeid(T))
  119|  1.36M|  {}
_ZNK2BT3Any7convertIlEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEPNSt9enable_ifIXsr3std13is_arithmeticIS5_EE5valueEvE4typeE:
  487|  2.15k|{
  488|  2.15k|  using SafeAny::details::convertNumber;
  489|  2.15k|  DST out;
  490|       |
  491|  2.15k|  const auto& type = _any.type();
  492|       |
  493|  2.15k|  if(type == typeid(int64_t))
  ------------------
  |  Branch (493:6): [True: 0, False: 2.15k]
  ------------------
  494|      0|  {
  495|      0|    convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
  496|      0|  }
  497|  2.15k|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (497:11): [True: 0, False: 2.15k]
  ------------------
  498|      0|  {
  499|      0|    convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
  500|      0|  }
  501|  2.15k|  else if(type == typeid(double))
  ------------------
  |  Branch (501:11): [True: 2.15k, False: 0]
  ------------------
  502|  2.15k|  {
  503|  2.15k|    convertNumber<double, DST>(linb::any_cast<double>(_any), out);
  504|  2.15k|  }
  505|      0|  else
  506|      0|  {
  507|      0|    return nonstd::make_unexpected(errorMsg<DST>());
  508|      0|  }
  509|  2.15k|  return out;
  510|  2.15k|}
_ZN2BT3AnyC2ERKd:
   90|   160k|  explicit Any(const double& value) : _any(value), _original_type(typeid(double))
   91|   160k|  {}
_ZN2BT3AnyC2IbEERKT_PNSt9enable_ifIXoosr3std11is_integralIS2_EE5valuesr3std7is_enumIS2_EE5valueEvE4typeE:
  118|  5.48k|    : _any(int64_t(value)), _original_type(typeid(T))
  119|  5.48k|  {}
_ZN2BT3AnyC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  100|   117k|    : _any(SafeAny::SimpleString(str)), _original_type(typeid(std::string))
  101|   117k|  {}
_ZN2BT3AnyC2ERKS0_:
   83|  1.81M|  Any(const Any& other) : _any(other._any), _original_type(other._original_type)
   84|  1.81M|  {}
_ZN2BT3AnyC2EOS0_:
   87|  1.47M|    : _any(std::move(other._any)), _original_type(other._original_type)
   88|  1.47M|  {}
_ZN2BT3AnyC2ERKSt10type_index:
  121|  31.5k|  Any(const std::type_index& type) : _original_type(type)
  122|  31.5k|  {}
_ZNK2BT3Any4castINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEET_v:
  169|  39.6k|  {
  170|  39.6k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 39.6k, False: 0]
  ------------------
  171|  39.6k|    {
  172|  39.6k|      return res.value();
  173|  39.6k|    }
  174|      0|    else
  175|      0|    {
  176|      0|      throw std::runtime_error(res.error());
  177|      0|    }
  178|  39.6k|  }
_ZNK2BT3Any7tryCastINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEN6nonstd13expected_lite8expectedIT_S7_EEv:
  514|  39.6k|{
  515|  39.6k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  516|  39.6k|                                              "can not cast to reference");
  517|       |
  518|  39.6k|  if(_any.empty())
  ------------------
  |  Branch (518:6): [True: 0, False: 39.6k]
  ------------------
  519|      0|  {
  520|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  521|      0|  }
  522|       |
  523|  39.6k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (523:6): [True: 0, False: 39.6k]
  ------------------
  524|      0|  {
  525|      0|    return linb::any_cast<T>(_any);
  526|      0|  }
  527|       |
  528|       |  // special case when the output is an enum.
  529|       |  // We will try first a int conversion
  530|       |  if constexpr(std::is_enum_v<T>)
  531|       |  {
  532|       |    if(isNumber())
  533|       |    {
  534|       |      return static_cast<T>(convert<int>().value());
  535|       |    }
  536|       |    if(isString())
  537|       |    {
  538|       |      if(auto out = stringToNumber<int64_t>())
  539|       |      {
  540|       |        return static_cast<T>(out.value());
  541|       |      }
  542|       |    }
  543|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  544|       |  }
  545|       |
  546|  39.6k|  if(isString())
  ------------------
  |  Branch (546:6): [True: 36.2k, False: 3.41k]
  ------------------
  547|  36.2k|  {
  548|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  549|       |    {
  550|       |      if(auto out = stringToNumber<T>())
  551|       |      {
  552|       |        return out.value();
  553|       |      }
  554|       |      else
  555|       |      {
  556|       |        return out;
  557|       |      }
  558|       |    }
  559|  36.2k|  }
  560|       |
  561|  39.6k|  if(auto res = convert<T>())
  ------------------
  |  Branch (561:11): [True: 39.6k, False: 0]
  ------------------
  562|  39.6k|  {
  563|  39.6k|    return std::move(res.value());
  564|  39.6k|  }
  565|      0|  else
  566|      0|  {
  567|      0|    return res;
  568|      0|  }
  569|  39.6k|}
_ZNK2BT3Any7convertINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEN6nonstd13expected_lite8expectedIT_S7_EEPNSt9enable_ifIXsr3std7is_sameISB_S7_EE5valueEvE4typeE:
  397|  39.6k|{
  398|  39.6k|  const auto& type = _any.type();
  399|       |
  400|  39.6k|  if(type == typeid(SafeAny::SimpleString))
  ------------------
  |  Branch (400:6): [True: 36.2k, False: 3.41k]
  ------------------
  401|  36.2k|  {
  402|  36.2k|    return linb::any_cast<SafeAny::SimpleString>(_any).toStdString();
  403|  36.2k|  }
  404|  3.41k|  else if(type == typeid(int64_t))
  ------------------
  |  Branch (404:11): [True: 1.00k, False: 2.41k]
  ------------------
  405|  1.00k|  {
  406|  1.00k|    return std::to_string(linb::any_cast<int64_t>(_any));
  407|  1.00k|  }
  408|  2.41k|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (408:11): [True: 0, False: 2.41k]
  ------------------
  409|      0|  {
  410|      0|    return std::to_string(linb::any_cast<uint64_t>(_any));
  411|      0|  }
  412|  2.41k|  else if(type == typeid(double))
  ------------------
  |  Branch (412:11): [True: 2.41k, False: 0]
  ------------------
  413|  2.41k|  {
  414|  2.41k|    return std::to_string(linb::any_cast<double>(_any));
  415|  2.41k|  }
  416|       |
  417|      0|  return nonstd::make_unexpected(errorMsg<DST>());
  418|  39.6k|}
_ZNK2BT3Any6isTypeIN7SafeAny12SimpleStringEEEbv:
  148|    698|  {
  149|    698|    return _original_type == typeid(T);
  150|    698|  }
_ZNK2BT3Any4castIN7SafeAny12SimpleStringEEET_v:
  169|  15.8k|  {
  170|  15.8k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 15.8k, False: 0]
  ------------------
  171|  15.8k|    {
  172|  15.8k|      return res.value();
  173|  15.8k|    }
  174|      0|    else
  175|      0|    {
  176|      0|      throw std::runtime_error(res.error());
  177|      0|    }
  178|  15.8k|  }
_ZNK2BT3Any7tryCastIN7SafeAny12SimpleStringEEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  514|  15.8k|{
  515|  15.8k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  516|  15.8k|                                              "can not cast to reference");
  517|       |
  518|  15.8k|  if(_any.empty())
  ------------------
  |  Branch (518:6): [True: 0, False: 15.8k]
  ------------------
  519|      0|  {
  520|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  521|      0|  }
  522|       |
  523|  15.8k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (523:6): [True: 15.8k, False: 0]
  ------------------
  524|  15.8k|  {
  525|  15.8k|    return linb::any_cast<T>(_any);
  526|  15.8k|  }
  527|       |
  528|       |  // special case when the output is an enum.
  529|       |  // We will try first a int conversion
  530|       |  if constexpr(std::is_enum_v<T>)
  531|       |  {
  532|       |    if(isNumber())
  533|       |    {
  534|       |      return static_cast<T>(convert<int>().value());
  535|       |    }
  536|       |    if(isString())
  537|       |    {
  538|       |      if(auto out = stringToNumber<int64_t>())
  539|       |      {
  540|       |        return static_cast<T>(out.value());
  541|       |      }
  542|       |    }
  543|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  544|       |  }
  545|       |
  546|      0|  if(isString())
  ------------------
  |  Branch (546:6): [True: 0, False: 0]
  ------------------
  547|      0|  {
  548|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  549|       |    {
  550|       |      if(auto out = stringToNumber<T>())
  551|       |      {
  552|       |        return out.value();
  553|       |      }
  554|       |      else
  555|       |      {
  556|       |        return out;
  557|       |      }
  558|       |    }
  559|      0|  }
  560|       |
  561|      0|  if(auto res = convert<T>())
  ------------------
  |  Branch (561:11): [True: 0, False: 0]
  ------------------
  562|      0|  {
  563|      0|    return std::move(res.value());
  564|      0|  }
  565|      0|  else
  566|      0|  {
  567|      0|    return res;
  568|      0|  }
  569|      0|}
_ZNK2BT3Any4castIbEET_v:
  169|  2.59k|  {
  170|  2.59k|    if(auto res = tryCast<T>())
  ------------------
  |  Branch (170:13): [True: 2.45k, False: 139]
  ------------------
  171|  2.45k|    {
  172|  2.45k|      return res.value();
  173|  2.45k|    }
  174|    139|    else
  175|    139|    {
  176|    139|      throw std::runtime_error(res.error());
  177|    139|    }
  178|  2.59k|  }
_ZNK2BT3Any7tryCastIbEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEv:
  514|  2.59k|{
  515|  2.59k|  static_assert(!std::is_reference<T>::value, "Any::cast uses value semantic, "
  516|  2.59k|                                              "can not cast to reference");
  517|       |
  518|  2.59k|  if(_any.empty())
  ------------------
  |  Branch (518:6): [True: 0, False: 2.59k]
  ------------------
  519|      0|  {
  520|      0|    throw std::runtime_error("Any::cast failed because it is empty");
  521|      0|  }
  522|       |
  523|  2.59k|  if(castedType() == typeid(T))
  ------------------
  |  Branch (523:6): [True: 0, False: 2.59k]
  ------------------
  524|      0|  {
  525|      0|    return linb::any_cast<T>(_any);
  526|      0|  }
  527|       |
  528|       |  // special case when the output is an enum.
  529|       |  // We will try first a int conversion
  530|       |  if constexpr(std::is_enum_v<T>)
  531|       |  {
  532|       |    if(isNumber())
  533|       |    {
  534|       |      return static_cast<T>(convert<int>().value());
  535|       |    }
  536|       |    if(isString())
  537|       |    {
  538|       |      if(auto out = stringToNumber<int64_t>())
  539|       |      {
  540|       |        return static_cast<T>(out.value());
  541|       |      }
  542|       |    }
  543|       |    return nonstd::make_unexpected("Any::cast failed to cast to enum type");
  544|       |  }
  545|       |
  546|  2.59k|  if(isString())
  ------------------
  |  Branch (546:6): [True: 0, False: 2.59k]
  ------------------
  547|      0|  {
  548|       |    if constexpr(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>)
  549|       |    {
  550|       |      if(auto out = stringToNumber<T>())
  551|       |      {
  552|       |        return out.value();
  553|       |      }
  554|       |      else
  555|       |      {
  556|       |        return out;
  557|       |      }
  558|       |    }
  559|      0|  }
  560|       |
  561|  2.59k|  if(auto res = convert<T>())
  ------------------
  |  Branch (561:11): [True: 2.45k, False: 139]
  ------------------
  562|  2.45k|  {
  563|  2.45k|    return std::move(res.value());
  564|  2.45k|  }
  565|    139|  else
  566|    139|  {
  567|    139|    return res;
  568|    139|  }
  569|  2.59k|}
_ZNK2BT3Any7convertIbEEN6nonstd13expected_lite8expectedIT_NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEEPNSt9enable_ifIXsr3std13is_arithmeticIS5_EE5valueEvE4typeE:
  487|  2.59k|{
  488|  2.59k|  using SafeAny::details::convertNumber;
  489|  2.59k|  DST out;
  490|       |
  491|  2.59k|  const auto& type = _any.type();
  492|       |
  493|  2.59k|  if(type == typeid(int64_t))
  ------------------
  |  Branch (493:6): [True: 1.56k, False: 1.03k]
  ------------------
  494|  1.56k|  {
  495|  1.56k|    convertNumber<int64_t, DST>(linb::any_cast<int64_t>(_any), out);
  496|  1.56k|  }
  497|  1.03k|  else if(type == typeid(uint64_t))
  ------------------
  |  Branch (497:11): [True: 0, False: 1.03k]
  ------------------
  498|      0|  {
  499|      0|    convertNumber<uint64_t, DST>(linb::any_cast<uint64_t>(_any), out);
  500|      0|  }
  501|  1.03k|  else if(type == typeid(double))
  ------------------
  |  Branch (501:11): [True: 1.03k, False: 0]
  ------------------
  502|  1.03k|  {
  503|  1.03k|    convertNumber<double, DST>(linb::any_cast<double>(_any), out);
  504|  1.03k|  }
  505|      0|  else
  506|      0|  {
  507|      0|    return nonstd::make_unexpected(errorMsg<DST>());
  508|      0|  }
  509|  2.59k|  return out;
  510|  2.59k|}

_ZN7SafeAny12SimpleStringC2ERKS0_:
   33|   401k|  SimpleString(const SimpleString& other) : SimpleString(other.data(), other.size())
   34|   401k|  {}
_ZNK7SafeAny12SimpleString4dataEv:
   87|   456k|  {
   88|   456k|    if(isSOO())
  ------------------
  |  Branch (88:8): [True: 357k, False: 98.7k]
  ------------------
   89|   357k|    {
   90|   357k|      return _storage.soo.data;
   91|   357k|    }
   92|  98.7k|    else
   93|  98.7k|    {
   94|  98.7k|      return _storage.str.data;
   95|  98.7k|    }
   96|   456k|  }
_ZNK7SafeAny12SimpleString5isSOOEv:
  155|  1.78M|  {
  156|  1.78M|    return (_storage.soo.capacity_left & IS_LONG_BIT) == 0;
  157|  1.78M|  }
_ZNK7SafeAny12SimpleString4sizeEv:
   99|   507k|  {
  100|   507k|    if(isSOO())
  ------------------
  |  Branch (100:8): [True: 385k, False: 122k]
  ------------------
  101|   385k|    {
  102|   385k|      return CAPACITY - _storage.soo.capacity_left;
  103|   385k|    }
  104|   122k|    else
  105|   122k|    {
  106|   122k|      return _storage.str.size & LONG_MASK;
  107|   122k|    }
  108|   507k|  }
_ZN7SafeAny12SimpleStringC2EPKcm:
   64|   518k|  {
   65|   518k|    createImpl(input_data, size);
   66|   518k|  }
_ZN7SafeAny12SimpleString10createImplEPKcm:
  184|   518k|  {
  185|   518k|    if(size > MAX_SIZE)
  ------------------
  |  Branch (185:8): [True: 13, False: 518k]
  ------------------
  186|     13|    {
  187|     13|      throw std::invalid_argument("size too large for a simple string");
  188|     13|    }
  189|       |
  190|   518k|    if(size > CAPACITY)
  ------------------
  |  Branch (190:8): [True: 103k, False: 415k]
  ------------------
  191|   103k|    {
  192|   103k|      _storage.str.size = size;
  193|   103k|      _storage.soo.capacity_left = IS_LONG_BIT;
  194|   103k|      _storage.str.data = new char[size + 1];  // NOLINT(cppcoreguidelines-owning-memory)
  195|   103k|      std::memcpy(_storage.str.data, input_data, size);
  196|   103k|      _storage.str.data[size] = '\0';
  197|   103k|    }
  198|   415k|    else
  199|   415k|    {
  200|   415k|      _storage.soo.capacity_left = uint8_t(CAPACITY - size);
  201|   415k|      if(size > 0)
  ------------------
  |  Branch (201:10): [True: 197k, False: 218k]
  ------------------
  202|   197k|      {
  203|   197k|        std::memcpy(_storage.soo.data, input_data, size);
  204|   197k|      }
  205|   415k|      if(size < CAPACITY)
  ------------------
  |  Branch (205:10): [True: 413k, False: 2.36k]
  ------------------
  206|   413k|      {
  207|   413k|        _storage.soo.data[size] = '\0';
  208|   413k|      }
  209|   415k|    }
  210|   518k|  }
_ZNK7SafeAny12SimpleString11toStdStringB5cxx11Ev:
   78|  43.5k|  {
   79|  43.5k|    return size() > 0 ? std::string(data(), size()) : std::string();
  ------------------
  |  Branch (79:12): [True: 39.9k, False: 3.53k]
  ------------------
   80|  43.5k|  }
_ZN7SafeAny12SimpleStringD2Ev:
   69|   822k|  {
   70|   822k|    if(!isSOO())
  ------------------
  |  Branch (70:8): [True: 103k, False: 719k]
  ------------------
   71|   103k|    {
   72|   103k|      delete[] _storage.str.data;
   73|   103k|    }
   74|   822k|    _storage.soo.capacity_left = CAPACITY;
   75|   822k|  }
_ZN7SafeAny12SimpleStringC2ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   27|   117k|  SimpleString(const std::string& str) : SimpleString(str.data(), str.size())
   28|   117k|  {}
_ZN7SafeAny12SimpleStringC2EOS0_:
   46|   303k|  SimpleString(SimpleString&& other) noexcept : SimpleString()
   47|   303k|  {
   48|   303k|    std::swap(_storage, other._storage);
   49|   303k|  }
_ZN7SafeAny12SimpleStringC2Ev:
   22|   303k|  {
   23|   303k|    _storage.soo.capacity_left = CAPACITY;
   24|   303k|    _storage.soo.data[0] = '\0';
   25|   303k|  }
_ZNK7SafeAny12SimpleStringeqERKS0_:
  111|  2.06k|  {
  112|  2.06k|    const size_t N = size();
  113|  2.06k|    return other.size() == N && std::strncmp(data(), other.data(), N) == 0;
  ------------------
  |  Branch (113:12): [True: 1.57k, False: 490]
  |  Branch (113:33): [True: 918, False: 656]
  ------------------
  114|  2.06k|  }
_ZNK7SafeAny12SimpleStringleERKS0_:
  123|  1.47k|  {
  124|  1.47k|    return !(*this > other);
  125|  1.47k|  }
_ZNK7SafeAny12SimpleStringgeERKS0_:
  128|  1.56k|  {
  129|  1.56k|    return !(*this < other);
  130|  1.56k|  }
_ZNK7SafeAny12SimpleStringltERKS0_:
  133|  3.04k|  {
  134|  3.04k|    const size_t min_size = std::min(size(), other.size());
  135|  3.04k|    int cmp = std::memcmp(data(), other.data(), min_size);
  136|  3.04k|    if(cmp != 0)
  ------------------
  |  Branch (136:8): [True: 1.15k, False: 1.89k]
  ------------------
  137|  1.15k|    {
  138|  1.15k|      return cmp < 0;
  139|  1.15k|    }
  140|  1.89k|    return size() < other.size();
  141|  3.04k|  }
_ZNK7SafeAny12SimpleStringgtERKS0_:
  144|  2.83k|  {
  145|  2.83k|    const size_t min_size = std::min(size(), other.size());
  146|  2.83k|    int cmp = std::memcmp(data(), other.data(), min_size);
  147|  2.83k|    if(cmp != 0)
  ------------------
  |  Branch (147:8): [True: 1.28k, False: 1.54k]
  ------------------
  148|  1.28k|    {
  149|  1.28k|      return cmp > 0;
  150|  1.28k|    }
  151|  1.54k|    return size() > other.size();
  152|  2.83k|  }

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

_ZN2BT17convertFromStringIdEET_St17basic_string_viewIcSt11char_traitsIcEE:
  201|  5.14k|{
  202|       |#if __cpp_lib_to_chars >= 201611L
  203|       |  // from_chars is locale-independent and thread-safe
  204|       |  double result = 0;
  205|       |  const auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
  206|       |  if(ec != std::errc())
  207|       |  {
  208|       |    throw RuntimeError(StrCat("Can't convert string [", str, "] to double"));
  209|       |  }
  210|       |  return result;
  211|       |#else
  212|       |  // Fallback: stod is locale-dependent, so force "C" locale.
  213|       |  // See issue #120.  Note: setlocale is not thread-safe.
  214|  5.14k|  const std::string old_locale = setlocale(LC_NUMERIC, nullptr);
  215|  5.14k|  std::ignore = setlocale(LC_NUMERIC, "C");
  216|  5.14k|  const std::string str_copy(str.data(), str.size());
  217|  5.14k|  const double val = std::stod(str_copy);
  218|       |  std::ignore = setlocale(LC_NUMERIC, old_locale.c_str());
  219|  5.14k|  return val;
  220|  5.14k|#endif
  221|  5.14k|}
_ZNK2BT8TypeInfo4typeEv:
  438|  40.1k|{
  439|  40.1k|  return type_info_;
  440|  40.1k|}
_ZN2BT9StartWithESt17basic_string_viewIcSt11char_traitsIcEEc:
  592|   390k|{
  593|   390k|  return str.size() >= 1 && str[0] == prefix;
  ------------------
  |  Branch (593:10): [True: 238k, False: 152k]
  |  Branch (593:29): [True: 161k, False: 77.1k]
  ------------------
  594|   390k|}

_ZN2BT10Blackboard12getAnyLockedERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   25|   165k|{
   26|   165k|  if(auto entry = getEntry(key))
  ------------------
  |  Branch (26:11): [True: 164k, False: 540]
  ------------------
   27|   164k|  {
   28|   164k|    return AnyPtrLocked(&entry->value, &entry->entry_mutex);
   29|   164k|  }
   30|    540|  return {};
   31|   165k|}
_ZNK2BT10Blackboard8getEntryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   55|   359k|{
   56|       |  // special syntax: "@" will always refer to the root BB
   57|   359k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (57:6): [True: 158k, False: 200k]
  ------------------
   58|   158k|  {
   59|   158k|    return rootBlackboard()->getEntry(key.substr(1, key.size() - 1));
   60|   158k|  }
   61|       |
   62|   200k|  {
   63|   200k|    const std::shared_lock<std::shared_mutex> storage_lock(storage_mutex_);
   64|   200k|    auto it = storage_.find(key);
   65|   200k|    if(it != storage_.end())
  ------------------
  |  Branch (65:8): [True: 190k, False: 10.2k]
  ------------------
   66|   190k|    {
   67|   190k|      return it->second;
   68|   190k|    }
   69|   200k|  }
   70|       |  // not found. Try autoremapping
   71|  10.2k|  if(auto parent = parent_bb_.lock())
  ------------------
  |  Branch (71:11): [True: 0, False: 10.2k]
  ------------------
   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.2k|  return {};
   85|  10.2k|}
_ZN2BT10Blackboard8getEntryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   88|   200k|{
   89|   200k|  return static_cast<const Blackboard&>(*this).getEntry(key);
   90|   200k|}
_ZN2BT10Blackboard9entryInfoERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
   93|    673|{
   94|    673|  auto entry = getEntry(key);
   95|    673|  return (!entry) ? nullptr : &(entry->info);
  ------------------
  |  Branch (95:10): [True: 0, False: 673]
  ------------------
   96|    673|}
_ZN2BT10Blackboard11createEntryERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_8TypeInfoE:
  165|  9.63k|{
  166|  9.63k|  if(StartWith(key, '@'))
  ------------------
  |  Branch (166:6): [True: 2.88k, False: 6.74k]
  ------------------
  167|  2.88k|  {
  168|  2.88k|    if(key.find('@', 1) != std::string::npos)
  ------------------
  |  Branch (168:8): [True: 0, False: 2.88k]
  ------------------
  169|      0|    {
  170|      0|      throw LogicError("Character '@' used multiple times in the key");
  171|      0|    }
  172|  2.88k|    rootBlackboard()->createEntryImpl(key.substr(1, key.size() - 1), info);
  173|  2.88k|  }
  174|  6.74k|  else
  175|  6.74k|  {
  176|  6.74k|    createEntryImpl(key, info);
  177|  6.74k|  }
  178|  9.63k|}
_ZN2BT10Blackboard15createEntryImplERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKNS_8TypeInfoE:
  284|  31.5k|{
  285|  31.5k|  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.5k|  auto storage_it = storage_.find(key);
  291|  31.5k|  if(storage_it != storage_.end())
  ------------------
  |  Branch (291:6): [True: 0, False: 31.5k]
  ------------------
  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.5k|  auto remapping_it = internal_to_external_.find(key);
  310|  31.5k|  if(remapping_it != internal_to_external_.end())
  ------------------
  |  Branch (310:6): [True: 0, False: 31.5k]
  ------------------
  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.5k|  if(autoremapping_ && !IsPrivateKey(key))
  ------------------
  |  Branch (320:6): [True: 0, False: 31.5k]
  |  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.5k|  auto entry = std::make_shared<Entry>(info);
  331|       |  // even if empty, let's assign to it a default type
  332|  31.5k|  entry->value = Any(info.type());
  333|  31.5k|  storage_.insert({ key, entry });
  334|  31.5k|  return entry;
  335|  31.5k|}
_ZN2BT10Blackboard14rootBlackboardEv:
  374|  2.88k|{
  375|  2.88k|  auto bb = static_cast<const Blackboard&>(*this).rootBlackboard();
  376|       |  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
  377|  2.88k|  return const_cast<Blackboard*>(bb);
  378|  2.88k|}
_ZNK2BT10Blackboard14rootBlackboardEv:
  381|   161k|{
  382|   161k|  const Blackboard* bb = this;
  383|   161k|  Blackboard::Ptr prev = parent_bb_.lock();
  384|   161k|  while(prev)
  ------------------
  |  Branch (384:9): [True: 0, False: 161k]
  ------------------
  385|      0|  {
  386|      0|    bb = prev.get();
  387|      0|    prev = bb->parent_bb_.lock();
  388|      0|  }
  389|   161k|  return bb;
  390|   161k|}

_ZN2BT9Scripting15parseStatementsERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  422|  12.1k|{
  423|  12.1k|  auto tokens = tokenize(script);
  424|  12.1k|  ScriptParser parser(std::move(tokens));
  425|  12.1k|  return parser.parseAll();
  426|  12.1k|}
_ZN2BT11ParseScriptERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  433|  6.62k|{
  434|  6.62k|  try
  435|  6.62k|  {
  436|  6.62k|    auto exprs = Scripting::parseStatements(script);
  437|  6.62k|    if(exprs.empty())
  ------------------
  |  Branch (437:8): [True: 52, False: 6.57k]
  ------------------
  438|     52|    {
  439|     52|      return nonstd::make_unexpected("Empty Script");
  440|     52|    }
  441|  6.57k|    return [exprs = std::move(exprs), script](Ast::Environment& env) {
  442|  6.57k|      try
  443|  6.57k|      {
  444|  6.57k|        for(size_t i = 0; i < exprs.size() - 1; ++i)
  445|  6.57k|        {
  446|  6.57k|          exprs[i]->evaluate(env);
  447|  6.57k|        }
  448|  6.57k|        return exprs.back()->evaluate(env);
  449|  6.57k|      }
  450|  6.57k|      catch(RuntimeError& err)
  451|  6.57k|      {
  452|  6.57k|        throw RuntimeError(StrCat("Error in script [", script, "]\n", err.what()));
  453|  6.57k|      }
  454|  6.57k|    };
  455|  6.62k|  }
  456|  6.62k|  catch(RuntimeError& err)
  457|  6.62k|  {
  458|  2.58k|    return nonstd::make_unexpected(err.what());
  459|  2.58k|  }
  460|  6.62k|}
_ZN2BT21ParseScriptAndExecuteERNS_3Ast11EnvironmentERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  463|  5.30k|{
  464|  5.30k|  auto executor = ParseScript(script);
  465|  5.30k|  if(executor)
  ------------------
  |  Branch (465:6): [True: 3.98k, False: 1.32k]
  ------------------
  466|  3.98k|  {
  467|  3.98k|    try
  468|  3.98k|    {
  469|  3.98k|      return executor.value()(env);
  470|  3.98k|    }
  471|  3.98k|    catch(RuntimeError& err)
  472|  3.98k|    {
  473|    978|      return nonstd::make_unexpected(err.what());
  474|    978|    }
  475|  3.98k|  }
  476|  1.32k|  return nonstd::make_unexpected(executor.error());
  477|  5.30k|}
_ZN2BT14ValidateScriptERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  480|  5.48k|{
  481|  5.48k|  try
  482|  5.48k|  {
  483|  5.48k|    auto exprs = Scripting::parseStatements(script);
  484|  5.48k|    if(exprs.empty())
  ------------------
  |  Branch (484:8): [True: 26, False: 5.46k]
  ------------------
  485|     26|    {
  486|     26|      return nonstd::make_unexpected("Empty Script");
  487|     26|    }
  488|  5.46k|    return {};
  489|  5.48k|  }
  490|  5.48k|  catch(RuntimeError& err)
  491|  5.48k|  {
  492|  1.29k|    return nonstd::make_unexpected(err.what());
  493|  1.29k|  }
  494|  5.48k|}
_ZN2BT9Scripting12ScriptParserC2ESt6vectorINS0_5TokenESaIS3_EE:
   28|  12.1k|  explicit ScriptParser(std::vector<Token> tokens) : tokens_(std::move(tokens))
   29|  12.1k|  {}
_ZN2BT9Scripting12ScriptParser8parseAllEv:
   32|  12.1k|  {
   33|  12.1k|    std::vector<Ast::expr_ptr> stmts;
   34|  4.77M|    while(!atEnd())
  ------------------
  |  Branch (34:11): [True: 4.75M, False: 12.1k]
  ------------------
   35|  4.75M|    {
   36|  4.75M|      stmts.push_back(parseExpr(0));
   37|       |      // consume optional semicolons between statements
   38|  4.77M|      while(check(TokenType::Semicolon))
  ------------------
  |  Branch (38:13): [True: 11.2k, False: 4.75M]
  ------------------
   39|  11.2k|      {
   40|  11.2k|        advance();
   41|  11.2k|      }
   42|  4.75M|    }
   43|  12.1k|    return stmts;
   44|  12.1k|  }
_ZNK2BT9Scripting12ScriptParser5atEndEv:
   73|  13.0M|  {
   74|  13.0M|    return peek().type == TokenType::EndOfInput;
   75|  13.0M|  }
_ZNK2BT9Scripting12ScriptParser4peekEv:
   60|  32.4M|  {
   61|  32.4M|    return tokens_[current_];
   62|  32.4M|  }
_ZN2BT9Scripting12ScriptParser9parseExprEi:
  256|  6.62M|  {
  257|  6.62M|    auto left = parsePrefix();
  258|       |
  259|  6.75M|    while(true)
  ------------------
  |  Branch (259:11): [True: 6.51M, Folded]
  ------------------
  260|  6.51M|    {
  261|  6.51M|      auto tokType = peek().type;
  262|  6.51M|      int lbp = leftBP(tokType);
  263|  6.51M|      if(lbp < 0 || lbp < minBP)
  ------------------
  |  Branch (263:10): [True: 4.81M, False: 1.69M]
  |  Branch (263:21): [True: 1.49M, False: 196k]
  ------------------
  264|  6.31M|      {
  265|  6.31M|        break;
  266|  6.31M|      }
  267|       |
  268|       |      // Assignment (non-associative: parse once, then break)
  269|   196k|      if(isAssignment(tokType))
  ------------------
  |  Branch (269:10): [True: 65.9k, False: 130k]
  ------------------
  270|  65.9k|      {
  271|  65.9k|        left = parseAssignment(std::move(left));
  272|  65.9k|        break;
  273|  65.9k|      }
  274|       |
  275|       |      // Ternary (non-associative: parse once, then break)
  276|   130k|      if(tokType == TokenType::Question)
  ------------------
  |  Branch (276:10): [True: 2.78k, False: 127k]
  ------------------
  277|  2.78k|      {
  278|  2.78k|        left = parseTernary(std::move(left));
  279|  2.78k|        break;
  280|  2.78k|      }
  281|       |
  282|       |      // Chained comparison
  283|   127k|      if(isComparison(tokType))
  ------------------
  |  Branch (283:10): [True: 40.8k, False: 87.0k]
  ------------------
  284|  40.8k|      {
  285|  40.8k|        left = parseChainedComparison(std::move(left));
  286|  40.8k|        continue;
  287|  40.8k|      }
  288|       |
  289|       |      // Regular left-associative binary operator
  290|  87.0k|      const auto& opTok = advance();
  291|       |      // Right BP = LBP + 1 for left-associativity
  292|  87.0k|      auto right = parseExpr(lbp + 1);
  293|  87.0k|      left = makeBinary(std::move(left), opTok.type, std::move(right));
  294|  87.0k|    }
  295|       |
  296|  6.62M|    return left;
  297|  6.62M|  }
_ZN2BT9Scripting12ScriptParser11parsePrefixEv:
  164|  6.62M|  {
  165|  6.62M|    const auto& tok = peek();
  166|       |
  167|       |    // Unary minus
  168|  6.62M|    if(tok.type == TokenType::Minus)
  ------------------
  |  Branch (168:8): [True: 35.2k, False: 6.58M]
  ------------------
  169|  35.2k|    {
  170|  35.2k|      advance();
  171|  35.2k|      auto operand = parseExpr(kPrefixBP);
  172|  35.2k|      return std::make_shared<Ast::ExprUnaryArithmetic>(Ast::ExprUnaryArithmetic::negate,
  173|  35.2k|                                                        std::move(operand));
  174|  35.2k|    }
  175|       |    // Bitwise complement
  176|  6.58M|    if(tok.type == TokenType::Tilde)
  ------------------
  |  Branch (176:8): [True: 73.6k, False: 6.51M]
  ------------------
  177|  73.6k|    {
  178|  73.6k|      advance();
  179|  73.6k|      auto operand = parseExpr(kPrefixBP);
  180|  73.6k|      return std::make_shared<Ast::ExprUnaryArithmetic>(
  181|  73.6k|          Ast::ExprUnaryArithmetic::complement, std::move(operand));
  182|  73.6k|    }
  183|       |    // Logical NOT
  184|  6.51M|    if(tok.type == TokenType::Bang)
  ------------------
  |  Branch (184:8): [True: 17.3k, False: 6.49M]
  ------------------
  185|  17.3k|    {
  186|  17.3k|      advance();
  187|  17.3k|      auto operand = parseExpr(kPrefixBP);
  188|  17.3k|      return std::make_shared<Ast::ExprUnaryArithmetic>(
  189|  17.3k|          Ast::ExprUnaryArithmetic::logical_not, std::move(operand));
  190|  17.3k|    }
  191|       |    // Parenthesized expression
  192|  6.49M|    if(tok.type == TokenType::LeftParen)
  ------------------
  |  Branch (192:8): [True: 121k, False: 6.37M]
  ------------------
  193|   121k|    {
  194|   121k|      advance();
  195|   121k|      auto expr = parseExpr(0);
  196|   121k|      expect(TokenType::RightParen, "expected ')'");
  197|   121k|      return expr;
  198|   121k|    }
  199|       |    // Boolean literal
  200|  6.37M|    if(tok.type == TokenType::Boolean)
  ------------------
  |  Branch (200:8): [True: 710, False: 6.37M]
  ------------------
  201|    710|    {
  202|    710|      advance();
  203|    710|      double val = (tok.text == "true") ? 1.0 : 0.0;
  ------------------
  |  Branch (203:20): [True: 492, False: 218]
  ------------------
  204|    710|      return std::make_shared<Ast::ExprLiteral>(Any(val));
  205|    710|    }
  206|       |    // Integer literal
  207|  6.37M|    if(tok.type == TokenType::Integer)
  ------------------
  |  Branch (207:8): [True: 1.36M, False: 5.00M]
  ------------------
  208|  1.36M|    {
  209|  1.36M|      advance();
  210|  1.36M|      int64_t val = 0;
  211|  1.36M|      const char* first = tok.text.data();
  212|  1.36M|      const char* last = first + tok.text.size();
  213|  1.36M|      if(tok.text.size() > 2 && tok.text[0] == '0' &&
  ------------------
  |  Branch (213:10): [True: 16.9k, False: 1.35M]
  |  Branch (213:33): [True: 3.04k, False: 13.8k]
  ------------------
  214|  3.04k|         (tok.text[1] == 'x' || tok.text[1] == 'X'))
  ------------------
  |  Branch (214:11): [True: 426, False: 2.62k]
  |  Branch (214:33): [True: 1.33k, False: 1.29k]
  ------------------
  215|  1.75k|      {
  216|  1.75k|        std::from_chars(first + 2, last, val, 16);
  217|  1.75k|      }
  218|  1.36M|      else
  219|  1.36M|      {
  220|  1.36M|        std::from_chars(first, last, val, 10);
  221|  1.36M|      }
  222|  1.36M|      return std::make_shared<Ast::ExprLiteral>(Any(val));
  223|  1.36M|    }
  224|       |    // Real literal
  225|  5.00M|    if(tok.type == TokenType::Real)
  ------------------
  |  Branch (225:8): [True: 5.14k, False: 5.00M]
  ------------------
  226|  5.14k|    {
  227|  5.14k|      advance();
  228|  5.14k|      double val = convertFromString<double>(tok.text);
  229|  5.14k|      return std::make_shared<Ast::ExprLiteral>(Any(val));
  230|  5.14k|    }
  231|       |    // String literal
  232|  5.00M|    if(tok.type == TokenType::String)
  ------------------
  |  Branch (232:8): [True: 96.6k, False: 4.90M]
  ------------------
  233|  96.6k|    {
  234|  96.6k|      advance();
  235|  96.6k|      return std::make_shared<Ast::ExprLiteral>(Any(std::string(tok.text)));
  236|  96.6k|    }
  237|       |    // Identifier
  238|  4.90M|    if(tok.type == TokenType::Identifier)
  ------------------
  |  Branch (238:8): [True: 4.90M, False: 3.52k]
  ------------------
  239|  4.90M|    {
  240|  4.90M|      advance();
  241|  4.90M|      return std::make_shared<Ast::ExprName>(std::string(tok.text));
  242|  4.90M|    }
  243|       |    // Error token from tokenizer
  244|  3.52k|    if(tok.type == TokenType::Error)
  ------------------
  |  Branch (244:8): [True: 1.74k, False: 1.77k]
  ------------------
  245|  1.74k|    {
  246|  1.74k|      throw RuntimeError(
  247|  1.74k|          StrCat("Invalid token '", tok.text, "' at position ", std::to_string(tok.pos)));
  248|  1.74k|    }
  249|       |
  250|  1.77k|    throw RuntimeError(StrCat("Expected operand at position ", std::to_string(tok.pos),
  251|  1.77k|                              " (got '", tok.text, "')"));
  252|  3.52k|  }
_ZN2BT9Scripting12ScriptParser6expectENS0_9TokenTypeEPKc:
   83|  4.77k|  {
   84|  4.77k|    if(!check(type))
  ------------------
  |  Branch (84:8): [True: 354, False: 4.42k]
  ------------------
   85|    354|    {
   86|    354|      throw RuntimeError(StrCat("Parse error at position ", std::to_string(peek().pos),
   87|    354|                                ": ", msg, " (got '", peek().text, "')"));
   88|    354|    }
   89|  4.42k|    return advance();
   90|  4.77k|  }
_ZN2BT9Scripting12ScriptParser6leftBPENS0_9TokenTypeE:
   97|  6.51M|  {
   98|  6.51M|    switch(type)
   99|  6.51M|    {
  100|       |      // Assignment (level 1, non-associative)
  101|  29.3k|      case TokenType::ColonEqual:
  ------------------
  |  Branch (101:7): [True: 29.3k, False: 6.48M]
  ------------------
  102|  46.6k|      case TokenType::Equal:
  ------------------
  |  Branch (102:7): [True: 17.2k, False: 6.49M]
  ------------------
  103|  62.4k|      case TokenType::PlusEqual:
  ------------------
  |  Branch (103:7): [True: 15.8k, False: 6.49M]
  ------------------
  104|  63.6k|      case TokenType::MinusEqual:
  ------------------
  |  Branch (104:7): [True: 1.19k, False: 6.51M]
  ------------------
  105|  64.6k|      case TokenType::StarEqual:
  ------------------
  |  Branch (105:7): [True: 1.03k, False: 6.51M]
  ------------------
  106|  66.5k|      case TokenType::SlashEqual:
  ------------------
  |  Branch (106:7): [True: 1.85k, False: 6.51M]
  ------------------
  107|  66.5k|        return kAssignmentBP;
  108|       |      // Ternary (level 2, non-associative)
  109|  4.01k|      case TokenType::Question:
  ------------------
  |  Branch (109:7): [True: 4.01k, False: 6.51M]
  ------------------
  110|  4.01k|        return kTernaryBP;
  111|       |      // Logical OR (level 3)
  112|  2.49k|      case TokenType::PipePipe:
  ------------------
  |  Branch (112:7): [True: 2.49k, False: 6.51M]
  ------------------
  113|  2.49k|        return 6;
  114|       |      // Logical AND (level 4)
  115|  2.37k|      case TokenType::AmpAmp:
  ------------------
  |  Branch (115:7): [True: 2.37k, False: 6.51M]
  ------------------
  116|  2.37k|        return 8;
  117|       |      // Comparison (level 5, chainable)
  118|  11.9k|      case TokenType::EqualEqual:
  ------------------
  |  Branch (118:7): [True: 11.9k, False: 6.50M]
  ------------------
  119|   137k|      case TokenType::BangEqual:
  ------------------
  |  Branch (119:7): [True: 125k, False: 6.38M]
  ------------------
  120|   299k|      case TokenType::Less:
  ------------------
  |  Branch (120:7): [True: 162k, False: 6.35M]
  ------------------
  121|  1.43M|      case TokenType::Greater:
  ------------------
  |  Branch (121:7): [True: 1.13M, False: 5.37M]
  ------------------
  122|  1.45M|      case TokenType::LessEqual:
  ------------------
  |  Branch (122:7): [True: 13.2k, False: 6.50M]
  ------------------
  123|  1.46M|      case TokenType::GreaterEqual:
  ------------------
  |  Branch (123:7): [True: 13.0k, False: 6.50M]
  ------------------
  124|  1.46M|        return kComparisonBP;
  125|       |      // Bitwise OR/XOR (level 6)
  126|   101k|      case TokenType::Pipe:
  ------------------
  |  Branch (126:7): [True: 101k, False: 6.41M]
  ------------------
  127|   102k|      case TokenType::Caret:
  ------------------
  |  Branch (127:7): [True: 862, False: 6.51M]
  ------------------
  128|   102k|        return 12;
  129|       |      // Bitwise AND (level 7)
  130|  3.40k|      case TokenType::Ampersand:
  ------------------
  |  Branch (130:7): [True: 3.40k, False: 6.51M]
  ------------------
  131|  3.40k|        return 14;
  132|       |      // Add/Sub/Concat (level 8)
  133|  22.3k|      case TokenType::Plus:
  ------------------
  |  Branch (133:7): [True: 22.3k, False: 6.49M]
  ------------------
  134|  26.9k|      case TokenType::Minus:
  ------------------
  |  Branch (134:7): [True: 4.57k, False: 6.51M]
  ------------------
  135|  46.7k|      case TokenType::DotDot:
  ------------------
  |  Branch (135:7): [True: 19.8k, False: 6.49M]
  ------------------
  136|  46.7k|        return 16;
  137|       |      // Mul/Div (level 9)
  138|  1.23k|      case TokenType::Star:
  ------------------
  |  Branch (138:7): [True: 1.23k, False: 6.51M]
  ------------------
  139|  3.91k|      case TokenType::Slash:
  ------------------
  |  Branch (139:7): [True: 2.67k, False: 6.51M]
  ------------------
  140|  3.91k|        return kMulDivBP;
  141|  4.81M|      default:
  ------------------
  |  Branch (141:7): [True: 4.81M, False: 1.69M]
  ------------------
  142|  4.81M|        return -1;
  143|  6.51M|    }
  144|  6.51M|  }
_ZN2BT9Scripting12ScriptParser12isAssignmentENS0_9TokenTypeE:
  154|   196k|  {
  155|   196k|    return type == TokenType::ColonEqual || type == TokenType::Equal ||
  ------------------
  |  Branch (155:12): [True: 29.1k, False: 167k]
  |  Branch (155:45): [True: 16.9k, False: 150k]
  ------------------
  156|   150k|           type == TokenType::PlusEqual || type == TokenType::MinusEqual ||
  ------------------
  |  Branch (156:12): [True: 15.8k, False: 134k]
  |  Branch (156:44): [True: 1.18k, False: 133k]
  ------------------
  157|   133k|           type == TokenType::StarEqual || type == TokenType::SlashEqual;
  ------------------
  |  Branch (157:12): [True: 1.03k, False: 132k]
  |  Branch (157:44): [True: 1.84k, False: 130k]
  ------------------
  158|   196k|  }
_ZN2BT9Scripting12ScriptParser15parseAssignmentESt10shared_ptrINS_3Ast8ExprBaseEE:
  300|  65.9k|  {
  301|  65.9k|    const auto& opTok = advance();
  302|  65.9k|    Ast::ExprAssignment::op_t op{};
  303|  65.9k|    switch(opTok.type)
  304|  65.9k|    {
  305|  29.1k|      case TokenType::ColonEqual:
  ------------------
  |  Branch (305:7): [True: 29.1k, False: 36.7k]
  ------------------
  306|  29.1k|        op = Ast::ExprAssignment::assign_create;
  307|  29.1k|        break;
  308|  16.9k|      case TokenType::Equal:
  ------------------
  |  Branch (308:7): [True: 16.9k, False: 49.0k]
  ------------------
  309|  16.9k|        op = Ast::ExprAssignment::assign_existing;
  310|  16.9k|        break;
  311|  15.8k|      case TokenType::PlusEqual:
  ------------------
  |  Branch (311:7): [True: 15.8k, False: 50.1k]
  ------------------
  312|  15.8k|        op = Ast::ExprAssignment::assign_plus;
  313|  15.8k|        break;
  314|  1.18k|      case TokenType::MinusEqual:
  ------------------
  |  Branch (314:7): [True: 1.18k, False: 64.7k]
  ------------------
  315|  1.18k|        op = Ast::ExprAssignment::assign_minus;
  316|  1.18k|        break;
  317|  1.03k|      case TokenType::StarEqual:
  ------------------
  |  Branch (317:7): [True: 1.03k, False: 64.9k]
  ------------------
  318|  1.03k|        op = Ast::ExprAssignment::assign_times;
  319|  1.03k|        break;
  320|  1.84k|      case TokenType::SlashEqual:
  ------------------
  |  Branch (320:7): [True: 1.84k, False: 64.1k]
  ------------------
  321|  1.84k|        op = Ast::ExprAssignment::assign_div;
  322|  1.84k|        break;
  323|      0|      default:
  ------------------
  |  Branch (323:7): [True: 0, False: 65.9k]
  ------------------
  324|      0|        throw RuntimeError("Internal error: unexpected assignment op");
  325|  65.9k|    }
  326|       |    // Parse RHS -- use minBP=0 to allow full expression
  327|  65.9k|    auto right = parseExpr(0);
  328|  65.9k|    return std::make_shared<Ast::ExprAssignment>(std::move(left), op, std::move(right));
  329|  65.9k|  }
_ZN2BT9Scripting12ScriptParser12parseTernaryESt10shared_ptrINS_3Ast8ExprBaseEE:
  332|  2.78k|  {
  333|  2.78k|    advance();                     // consume '?'
  334|  2.78k|    auto thenExpr = parseExpr(0);  // full expression inside
  335|  2.78k|    expect(TokenType::Colon, "expected ':' in ternary expression");
  336|  2.78k|    auto elseExpr = parseExpr(kTernaryBP);
  337|  2.78k|    return std::make_shared<Ast::ExprIf>(std::move(condition), std::move(thenExpr),
  338|  2.78k|                                         std::move(elseExpr));
  339|  2.78k|  }
_ZN2BT9Scripting12ScriptParser12isComparisonENS0_9TokenTypeE:
  147|  1.62M|  {
  148|  1.62M|    return type == TokenType::EqualEqual || type == TokenType::BangEqual ||
  ------------------
  |  Branch (148:12): [True: 15.4k, False: 1.61M]
  |  Branch (148:45): [True: 128k, False: 1.48M]
  ------------------
  149|  1.48M|           type == TokenType::Less || type == TokenType::Greater ||
  ------------------
  |  Branch (149:12): [True: 168k, False: 1.31M]
  |  Branch (149:39): [True: 1.14M, False: 166k]
  ------------------
  150|   166k|           type == TokenType::LessEqual || type == TokenType::GreaterEqual;
  ------------------
  |  Branch (150:12): [True: 17.2k, False: 149k]
  |  Branch (150:44): [True: 23.3k, False: 126k]
  ------------------
  151|  1.62M|  }
_ZN2BT9Scripting12ScriptParser22parseChainedComparisonESt10shared_ptrINS_3Ast8ExprBaseEE:
  342|  40.8k|  {
  343|  40.8k|    auto node = std::make_shared<Ast::ExprComparison>();
  344|  40.8k|    node->operands.push_back(std::move(first));
  345|       |
  346|  1.50M|    while(isComparison(peek().type))
  ------------------
  |  Branch (346:11): [True: 1.45M, False: 40.8k]
  ------------------
  347|  1.45M|    {
  348|  1.45M|      node->ops.push_back(mapComparisonOp(advance().type));
  349|       |      // Parse the next operand above comparison level
  350|       |      // so that arithmetic binds tighter
  351|  1.45M|      node->operands.push_back(parseExpr(kComparisonBP + 1));
  352|  1.45M|    }
  353|  40.8k|    return node;
  354|  40.8k|  }
_ZN2BT9Scripting12ScriptParser15mapComparisonOpENS0_9TokenTypeE:
  357|  1.45M|  {
  358|  1.45M|    switch(type)
  359|  1.45M|    {
  360|  11.8k|      case TokenType::EqualEqual:
  ------------------
  |  Branch (360:7): [True: 11.8k, False: 1.44M]
  ------------------
  361|  11.8k|        return Ast::ExprComparison::equal;
  362|   125k|      case TokenType::BangEqual:
  ------------------
  |  Branch (362:7): [True: 125k, False: 1.33M]
  ------------------
  363|   125k|        return Ast::ExprComparison::not_equal;
  364|   159k|      case TokenType::Less:
  ------------------
  |  Branch (364:7): [True: 159k, False: 1.29M]
  ------------------
  365|   159k|        return Ast::ExprComparison::less;
  366|  1.13M|      case TokenType::Greater:
  ------------------
  |  Branch (366:7): [True: 1.13M, False: 321k]
  ------------------
  367|  1.13M|        return Ast::ExprComparison::greater;
  368|  12.4k|      case TokenType::LessEqual:
  ------------------
  |  Branch (368:7): [True: 12.4k, False: 1.44M]
  ------------------
  369|  12.4k|        return Ast::ExprComparison::less_equal;
  370|  12.5k|      case TokenType::GreaterEqual:
  ------------------
  |  Branch (370:7): [True: 12.5k, False: 1.44M]
  ------------------
  371|  12.5k|        return Ast::ExprComparison::greater_equal;
  372|      0|      default:
  ------------------
  |  Branch (372:7): [True: 0, False: 1.45M]
  ------------------
  373|      0|        throw RuntimeError("Internal error: not a comparison op");
  374|  1.45M|    }
  375|  1.45M|  }
_ZN2BT9Scripting12ScriptParser10makeBinaryESt10shared_ptrINS_3Ast8ExprBaseEENS0_9TokenTypeES5_:
  379|  86.5k|  {
  380|  86.5k|    Ast::ExprBinaryArithmetic::op_t op{};
  381|  86.5k|    switch(opType)
  382|  86.5k|    {
  383|  13.8k|      case TokenType::Plus:
  ------------------
  |  Branch (383:7): [True: 13.8k, False: 72.7k]
  ------------------
  384|  13.8k|        op = Ast::ExprBinaryArithmetic::plus;
  385|  13.8k|        break;
  386|  2.49k|      case TokenType::Minus:
  ------------------
  |  Branch (386:7): [True: 2.49k, False: 84.0k]
  ------------------
  387|  2.49k|        op = Ast::ExprBinaryArithmetic::minus;
  388|  2.49k|        break;
  389|    731|      case TokenType::Star:
  ------------------
  |  Branch (389:7): [True: 731, False: 85.8k]
  ------------------
  390|    731|        op = Ast::ExprBinaryArithmetic::times;
  391|    731|        break;
  392|  1.45k|      case TokenType::Slash:
  ------------------
  |  Branch (392:7): [True: 1.45k, False: 85.0k]
  ------------------
  393|  1.45k|        op = Ast::ExprBinaryArithmetic::div;
  394|  1.45k|        break;
  395|  12.7k|      case TokenType::DotDot:
  ------------------
  |  Branch (395:7): [True: 12.7k, False: 73.7k]
  ------------------
  396|  12.7k|        op = Ast::ExprBinaryArithmetic::concat;
  397|  12.7k|        break;
  398|  1.39k|      case TokenType::Ampersand:
  ------------------
  |  Branch (398:7): [True: 1.39k, False: 85.1k]
  ------------------
  399|  1.39k|        op = Ast::ExprBinaryArithmetic::bit_and;
  400|  1.39k|        break;
  401|  50.7k|      case TokenType::Pipe:
  ------------------
  |  Branch (401:7): [True: 50.7k, False: 35.8k]
  ------------------
  402|  50.7k|        op = Ast::ExprBinaryArithmetic::bit_or;
  403|  50.7k|        break;
  404|    447|      case TokenType::Caret:
  ------------------
  |  Branch (404:7): [True: 447, False: 86.0k]
  ------------------
  405|    447|        op = Ast::ExprBinaryArithmetic::bit_xor;
  406|    447|        break;
  407|  1.43k|      case TokenType::AmpAmp:
  ------------------
  |  Branch (407:7): [True: 1.43k, False: 85.1k]
  ------------------
  408|  1.43k|        op = Ast::ExprBinaryArithmetic::logic_and;
  409|  1.43k|        break;
  410|  1.30k|      case TokenType::PipePipe:
  ------------------
  |  Branch (410:7): [True: 1.30k, False: 85.2k]
  ------------------
  411|  1.30k|        op = Ast::ExprBinaryArithmetic::logic_or;
  412|  1.30k|        break;
  413|      0|      default:
  ------------------
  |  Branch (413:7): [True: 0, False: 86.5k]
  ------------------
  414|      0|        throw RuntimeError("Internal error: unknown binary operator");
  415|  86.5k|    }
  416|  86.5k|    return std::make_shared<Ast::ExprBinaryArithmetic>(std::move(left), op,
  417|  86.5k|                                                       std::move(right));
  418|  86.5k|  }
_ZNK2BT9Scripting12ScriptParser5checkENS0_9TokenTypeE:
   78|  4.77M|  {
   79|  4.77M|    return peek().type == type;
   80|  4.77M|  }
_ZN2BT9Scripting12ScriptParser7advanceEv:
   65|  8.25M|  {
   66|  8.25M|    const Token& tok = tokens_[current_];
   67|  8.25M|    if(!atEnd())
  ------------------
  |  Branch (67:8): [True: 8.25M, False: 0]
  ------------------
   68|  8.25M|      current_++;
   69|  8.25M|    return tok;
   70|  8.25M|  }
script_parser.cpp:_ZZN2BT11ParseScriptERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEENK3$_0clERNS_3Ast11EnvironmentE:
  441|  3.98k|    return [exprs = std::move(exprs), script](Ast::Environment& env) {
  442|  3.98k|      try
  443|  3.98k|      {
  444|   171k|        for(size_t i = 0; i < exprs.size() - 1; ++i)
  ------------------
  |  Branch (444:27): [True: 167k, False: 3.98k]
  ------------------
  445|   167k|        {
  446|   167k|          exprs[i]->evaluate(env);
  447|   167k|        }
  448|  3.98k|        return exprs.back()->evaluate(env);
  449|  3.98k|      }
  450|  3.98k|      catch(RuntimeError& err)
  451|  3.98k|      {
  452|    978|        throw RuntimeError(StrCat("Error in script [", script, "]\n", err.what()));
  453|    978|      }
  454|  3.98k|    };

_ZN2BT9Scripting8tokenizeERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE:
  224|  12.1k|{
  225|  12.1k|  std::vector<Token> tokens;
  226|  12.1k|  const size_t len = source.size();
  227|  12.1k|  size_t i = 0;
  228|       |
  229|  38.4M|  while(i < len)
  ------------------
  |  Branch (229:9): [True: 38.4M, False: 12.1k]
  ------------------
  230|  38.4M|  {
  231|  38.4M|    const char c = source[i];
  232|       |
  233|       |    // Skip whitespace (space, tab, newline, carriage return)
  234|  38.4M|    if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
  ------------------
  |  Branch (234:8): [True: 4.93k, False: 38.4M]
  |  Branch (234:20): [True: 14.2k, False: 38.4M]
  |  Branch (234:33): [True: 269k, False: 38.1M]
  |  Branch (234:46): [True: 2.13k, False: 38.1M]
  ------------------
  235|   290k|    {
  236|   290k|      ++i;
  237|   290k|      continue;
  238|   290k|    }
  239|       |
  240|  38.1M|    const size_t start = i;
  241|       |
  242|       |    // Single-quoted string literal
  243|  38.1M|    if(c == '\'')
  ------------------
  |  Branch (243:8): [True: 343k, False: 37.7M]
  ------------------
  244|   343k|    {
  245|   343k|      ++i;
  246|  68.9M|      while(i < len && source[i] != '\'')
  ------------------
  |  Branch (246:13): [True: 68.9M, False: 340]
  |  Branch (246:24): [True: 68.6M, False: 343k]
  ------------------
  247|  68.6M|      {
  248|  68.6M|        ++i;
  249|  68.6M|      }
  250|   343k|      if(i < len)
  ------------------
  |  Branch (250:10): [True: 343k, False: 340]
  ------------------
  251|   343k|      {
  252|       |        // extract content without quotes
  253|   343k|        std::string_view text(&source[start + 1], i - start - 1);
  254|   343k|        tokens.push_back({ TokenType::String, text, start });
  255|   343k|        ++i;  // skip closing quote
  256|   343k|      }
  257|    340|      else
  258|    340|      {
  259|    340|        std::string_view text(&source[start], i - start);
  260|    340|        tokens.push_back({ TokenType::Error, text, start });
  261|    340|      }
  262|   343k|      continue;
  263|   343k|    }
  264|       |
  265|       |    // Number literal (integer or real)
  266|  37.7M|    if(isDigit(c))
  ------------------
  |  Branch (266:8): [True: 4.23M, False: 33.5M]
  ------------------
  267|  4.23M|    {
  268|  4.23M|      NumberResult nr;
  269|  4.23M|      const bool is_hex =
  270|  4.23M|          c == '0' && i + 1 < len && (source[i + 1] == 'x' || source[i + 1] == 'X');
  ------------------
  |  Branch (270:11): [True: 345k, False: 3.89M]
  |  Branch (270:23): [True: 345k, False: 709]
  |  Branch (270:39): [True: 83.7k, False: 261k]
  |  Branch (270:63): [True: 4.90k, False: 256k]
  ------------------
  271|  4.23M|      if(is_hex)
  ------------------
  |  Branch (271:10): [True: 88.6k, False: 4.15M]
  ------------------
  272|  88.6k|      {
  273|  88.6k|        nr = scanHexNumber(source, len, i);
  274|  88.6k|      }
  275|  4.15M|      else
  276|  4.15M|      {
  277|  4.15M|        nr = scanDecimalNumber(source, len, i);
  278|  4.15M|      }
  279|       |
  280|  4.23M|      std::string_view text(&source[start], i - start);
  281|  4.23M|      if(nr.has_error)
  ------------------
  |  Branch (281:10): [True: 363k, False: 3.87M]
  ------------------
  282|   363k|      {
  283|   363k|        tokens.push_back({ TokenType::Error, text, start });
  284|   363k|      }
  285|  3.87M|      else if(nr.is_real)
  ------------------
  |  Branch (285:15): [True: 51.4k, False: 3.82M]
  ------------------
  286|  51.4k|      {
  287|  51.4k|        tokens.push_back({ TokenType::Real, text, start });
  288|  51.4k|      }
  289|  3.82M|      else
  290|  3.82M|      {
  291|  3.82M|        tokens.push_back({ TokenType::Integer, text, start });
  292|  3.82M|      }
  293|  4.23M|      continue;
  294|  4.23M|    }
  295|       |
  296|       |    // Identifier or keyword (true/false)
  297|  33.5M|    if(isIdentStart(c))
  ------------------
  |  Branch (297:8): [True: 6.58M, False: 26.9M]
  ------------------
  298|  6.58M|    {
  299|  6.58M|      ++i;  // consume start character (may not be isIdentChar, e.g. '@')
  300|  52.9M|      while(i < len && isIdentChar(source[i]))
  ------------------
  |  Branch (300:13): [True: 52.9M, False: 2.75k]
  |  Branch (300:24): [True: 46.3M, False: 6.58M]
  ------------------
  301|  46.3M|      {
  302|  46.3M|        ++i;
  303|  46.3M|      }
  304|  6.58M|      if(std::string_view text(&source[start], i - start); text == "true" || text == "fal"
  ------------------
  |  Branch (304:60): [True: 8.97k, False: 6.57M]
  |  Branch (304:78): [True: 719, False: 6.57M]
  ------------------
  305|  6.57M|                                                                                     "se")
  306|  9.69k|      {
  307|  9.69k|        tokens.push_back({ TokenType::Boolean, text, start });
  308|  9.69k|      }
  309|  6.57M|      else
  310|  6.57M|      {
  311|  6.57M|        tokens.push_back({ TokenType::Identifier, text, start });
  312|  6.57M|      }
  313|  6.58M|      continue;
  314|  6.58M|    }
  315|       |
  316|       |    // Two-character operators (check before single-char)
  317|  26.9M|    if(i + 1 < len)
  ------------------
  |  Branch (317:8): [True: 26.9M, False: 2.14k]
  ------------------
  318|  26.9M|    {
  319|  26.9M|      TokenType two_char_type = matchTwoCharOp(c, source[i + 1]);
  320|  26.9M|      if(two_char_type != TokenType::Error)
  ------------------
  |  Branch (320:10): [True: 364k, False: 26.5M]
  ------------------
  321|   364k|      {
  322|   364k|        std::string_view text(&source[start], 2);
  323|   364k|        tokens.push_back({ two_char_type, text, start });
  324|   364k|        i += 2;
  325|   364k|        continue;
  326|   364k|      }
  327|  26.9M|    }
  328|       |
  329|       |    // Single-character operators and delimiters
  330|  26.6M|    std::string_view text(&source[start], 1);
  331|  26.6M|    tokens.push_back({ matchSingleCharOp(c), text, start });
  332|  26.6M|    ++i;
  333|  26.6M|  }
  334|       |
  335|       |  // Sentinel
  336|  12.1k|  tokens.push_back({ TokenType::EndOfInput, {}, i });
  337|  12.1k|  return tokens;
  338|  12.1k|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_17isDigitEc:
   34|  64.3M|{
   35|  64.3M|  return std::isdigit(static_cast<unsigned char>(c)) != 0;
   36|  64.3M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_113scanHexNumberERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmRm:
   59|  88.6k|{
   60|  88.6k|  NumberResult result;
   61|  88.6k|  i += 2;  // skip "0x"/"0X"
   62|  88.6k|  if(i >= len || !isHexDigit(source[i]))
  ------------------
  |  Branch (62:6): [True: 37, False: 88.6k]
  |  Branch (62:18): [True: 83.9k, False: 4.74k]
  ------------------
   63|  83.9k|  {
   64|  83.9k|    result.has_error = true;
   65|  83.9k|  }
   66|  4.74k|  else
   67|  4.74k|  {
   68|   140k|    while(i < len && isHexDigit(source[i]))
  ------------------
  |  Branch (68:11): [True: 139k, False: 513]
  |  Branch (68:22): [True: 135k, False: 4.22k]
  ------------------
   69|   135k|    {
   70|   135k|      ++i;
   71|   135k|    }
   72|  4.74k|  }
   73|       |  // Hex numbers don't support dot or exponent
   74|  88.6k|  if(i < len && (source[i] == '.' || isIdentChar(source[i])))
  ------------------
  |  Branch (74:6): [True: 88.1k, False: 550]
  |  Branch (74:18): [True: 276, False: 87.8k]
  |  Branch (74:38): [True: 79.1k, False: 8.75k]
  ------------------
   75|  79.3k|  {
   76|  79.3k|    result.has_error = true;
   77|  79.3k|    consumeTrailingGarbage(source, len, i);
   78|  79.3k|  }
   79|  88.6k|  return result;
   80|  88.6k|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_110isHexDigitEc:
   39|   228k|{
   40|   228k|  return std::isxdigit(static_cast<unsigned char>(c)) != 0;
   41|   228k|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_122consumeTrailingGarbageERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmRm:
   45|  81.7k|{
   46|   185k|  while(i < len && (isIdentChar(source[i]) || source[i] == '.'))
  ------------------
  |  Branch (46:9): [True: 185k, False: 183]
  |  Branch (46:21): [True: 103k, False: 82.0k]
  |  Branch (46:47): [True: 524, False: 81.5k]
  ------------------
   47|   103k|  {
   48|   103k|    ++i;
   49|   103k|  }
   50|  81.7k|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_117scanDecimalNumberERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEmRm:
   83|  4.15M|{
   84|  4.15M|  NumberResult result;
   85|       |
   86|       |  // Integer part
   87|  18.2M|  while(i < len && isDigit(source[i]))
  ------------------
  |  Branch (87:9): [True: 18.2M, False: 2.50k]
  |  Branch (87:20): [True: 14.1M, False: 4.14M]
  ------------------
   88|  14.1M|  {
   89|  14.1M|    ++i;
   90|  14.1M|  }
   91|       |  // Fractional part
   92|  4.15M|  if(i < len && source[i] == '.')
  ------------------
  |  Branch (92:6): [True: 4.14M, False: 2.50k]
  |  Branch (92:17): [True: 27.2k, False: 4.12M]
  ------------------
   93|  27.2k|  {
   94|       |    // Distinguish from ".." (concat operator)
   95|  27.2k|    if(i + 1 < len && source[i + 1] == '.')
  ------------------
  |  Branch (95:8): [True: 27.2k, False: 16]
  |  Branch (95:23): [True: 13.3k, False: 13.8k]
  ------------------
   96|  13.3k|    {
   97|       |      // Stop here: "65.." is Integer("65") + DotDot
   98|  13.3k|    }
   99|  13.9k|    else if(i + 1 < len && isDigit(source[i + 1]))
  ------------------
  |  Branch (99:13): [True: 13.8k, False: 16]
  |  Branch (99:28): [True: 11.5k, False: 2.30k]
  ------------------
  100|  11.5k|    {
  101|  11.5k|      result.is_real = true;
  102|  11.5k|      ++i;  // consume '.'
  103|  8.15M|      while(i < len && isDigit(source[i]))
  ------------------
  |  Branch (103:13): [True: 8.15M, False: 109]
  |  Branch (103:24): [True: 8.14M, False: 11.4k]
  ------------------
  104|  8.14M|      {
  105|  8.14M|        ++i;
  106|  8.14M|      }
  107|  11.5k|    }
  108|  2.31k|    else
  109|  2.31k|    {
  110|       |      // "65." or "65.x" -- incomplete real
  111|  2.31k|      result.has_error = true;
  112|  2.31k|      ++i;  // consume the dot
  113|  2.31k|      consumeTrailingGarbage(source, len, i);
  114|  2.31k|    }
  115|  27.2k|  }
  116|       |  // Exponent (only for decimal numbers)
  117|  4.15M|  if(!result.has_error && i < len && (source[i] == 'e' || source[i] == 'E'))
  ------------------
  |  Branch (117:6): [True: 4.14M, False: 2.31k]
  |  Branch (117:27): [True: 4.14M, False: 2.61k]
  |  Branch (117:39): [True: 2.22k, False: 4.14M]
  |  Branch (117:59): [True: 40.7k, False: 4.10M]
  ------------------
  118|  42.9k|  {
  119|  42.9k|    result.is_real = true;
  120|  42.9k|    ++i;  // consume 'e'/'E'
  121|  42.9k|    if(i < len && (source[i] == '+' || source[i] == '-'))
  ------------------
  |  Branch (121:8): [True: 42.9k, False: 34]
  |  Branch (121:20): [True: 375, False: 42.5k]
  |  Branch (121:40): [True: 419, False: 42.1k]
  ------------------
  122|    794|    {
  123|    794|      ++i;  // consume sign
  124|    794|    }
  125|  42.9k|    if(i >= len || !isDigit(source[i]))
  ------------------
  |  Branch (125:8): [True: 67, False: 42.9k]
  |  Branch (125:20): [True: 1.46k, False: 41.4k]
  ------------------
  126|  1.52k|    {
  127|  1.52k|      result.has_error = true;
  128|  1.52k|    }
  129|  41.4k|    else
  130|  41.4k|    {
  131|   113k|      while(i < len && isDigit(source[i]))
  ------------------
  |  Branch (131:13): [True: 113k, False: 303]
  |  Branch (131:24): [True: 72.1k, False: 41.1k]
  ------------------
  132|  72.1k|      {
  133|  72.1k|        ++i;
  134|  72.1k|      }
  135|  41.4k|    }
  136|  42.9k|  }
  137|       |  // Trailing alpha (e.g. "3foo", "65.43foo")
  138|  4.15M|  if(!result.has_error && i < len && isIdentStart(source[i]))
  ------------------
  |  Branch (138:6): [True: 4.14M, False: 3.84k]
  |  Branch (138:27): [True: 4.14M, False: 2.91k]
  |  Branch (138:38): [True: 275k, False: 3.86M]
  ------------------
  139|   275k|  {
  140|   275k|    result.has_error = true;
  141|  2.58M|    while(i < len && isIdentChar(source[i]))
  ------------------
  |  Branch (141:11): [True: 2.58M, False: 94]
  |  Branch (141:22): [True: 2.30M, False: 275k]
  ------------------
  142|  2.30M|    {
  143|  2.30M|      ++i;
  144|  2.30M|    }
  145|   275k|  }
  146|  4.15M|  return result;
  147|  4.15M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_112isIdentStartEc:
   24|  37.6M|{
   25|  37.6M|  return std::isalpha(static_cast<unsigned char>(c)) != 0 || c == '_' || c == '@';
  ------------------
  |  Branch (25:10): [True: 1.34M, False: 36.3M]
  |  Branch (25:62): [True: 1.24k, False: 36.3M]
  |  Branch (25:74): [True: 5.51M, False: 30.8M]
  ------------------
   26|  37.6M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_111isIdentCharEc:
   29|  55.7M|{
   30|  55.7M|  return std::isalnum(static_cast<unsigned char>(c)) != 0 || c == '_';
  ------------------
  |  Branch (30:10): [True: 48.8M, False: 6.95M]
  |  Branch (30:62): [True: 9.14k, False: 6.94M]
  ------------------
   31|  55.7M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_114matchTwoCharOpEcc:
  150|  26.9M|{
  151|  26.9M|  if(c == '.' && next == '.')
  ------------------
  |  Branch (151:6): [True: 101k, False: 26.8M]
  |  Branch (151:18): [True: 64.2k, False: 37.0k]
  ------------------
  152|  64.2k|    return TokenType::DotDot;
  153|  26.8M|  if(c == '&' && next == '&')
  ------------------
  |  Branch (153:6): [True: 16.9k, False: 26.8M]
  |  Branch (153:18): [True: 14.0k, False: 2.85k]
  ------------------
  154|  14.0k|    return TokenType::AmpAmp;
  155|  26.8M|  if(c == '|' && next == '|')
  ------------------
  |  Branch (155:6): [True: 59.0k, False: 26.8M]
  |  Branch (155:18): [True: 4.24k, False: 54.7k]
  ------------------
  156|  4.24k|    return TokenType::PipePipe;
  157|  26.8M|  if(c == '=' && next == '=')
  ------------------
  |  Branch (157:6): [True: 81.4k, False: 26.7M]
  |  Branch (157:18): [True: 15.9k, False: 65.4k]
  ------------------
  158|  15.9k|    return TokenType::EqualEqual;
  159|  26.8M|  if(c == '!' && next == '=')
  ------------------
  |  Branch (159:6): [True: 214k, False: 26.6M]
  |  Branch (159:18): [True: 146k, False: 67.2k]
  ------------------
  160|   146k|    return TokenType::BangEqual;
  161|  26.7M|  if(c == '<' && next == '=')
  ------------------
  |  Branch (161:6): [True: 205k, False: 26.5M]
  |  Branch (161:18): [True: 30.0k, False: 175k]
  ------------------
  162|  30.0k|    return TokenType::LessEqual;
  163|  26.6M|  if(c == '>' && next == '=')
  ------------------
  |  Branch (163:6): [True: 1.97M, False: 24.7M]
  |  Branch (163:18): [True: 13.9k, False: 1.96M]
  ------------------
  164|  13.9k|    return TokenType::GreaterEqual;
  165|  26.6M|  if(c == ':' && next == '=')
  ------------------
  |  Branch (165:6): [True: 60.9k, False: 26.6M]
  |  Branch (165:18): [True: 50.9k, False: 9.98k]
  ------------------
  166|  50.9k|    return TokenType::ColonEqual;
  167|  26.6M|  if(c == '+' && next == '=')
  ------------------
  |  Branch (167:6): [True: 38.2k, False: 26.5M]
  |  Branch (167:18): [True: 16.9k, False: 21.3k]
  ------------------
  168|  16.9k|    return TokenType::PlusEqual;
  169|  26.6M|  if(c == '-' && next == '=')
  ------------------
  |  Branch (169:6): [True: 113k, False: 26.4M]
  |  Branch (169:18): [True: 2.34k, False: 111k]
  ------------------
  170|  2.34k|    return TokenType::MinusEqual;
  171|  26.6M|  if(c == '*' && next == '=')
  ------------------
  |  Branch (171:6): [True: 3.61k, False: 26.5M]
  |  Branch (171:18): [True: 1.38k, False: 2.23k]
  ------------------
  172|  1.38k|    return TokenType::StarEqual;
  173|  26.6M|  if(c == '/' && next == '=')
  ------------------
  |  Branch (173:6): [True: 11.6k, False: 26.5M]
  |  Branch (173:18): [True: 3.21k, False: 8.39k]
  ------------------
  174|  3.21k|    return TokenType::SlashEqual;
  175|  26.5M|  return TokenType::Error;
  176|  26.6M|}
script_tokenizer.cpp:_ZN2BT9Scripting12_GLOBAL__N_117matchSingleCharOpEc:
  179|  26.6M|{
  180|  26.6M|  switch(c)
  181|  26.6M|  {
  182|  21.3k|    case '+':
  ------------------
  |  Branch (182:5): [True: 21.3k, False: 26.5M]
  ------------------
  183|  21.3k|      return TokenType::Plus;
  184|   111k|    case '-':
  ------------------
  |  Branch (184:5): [True: 111k, False: 26.4M]
  ------------------
  185|   111k|      return TokenType::Minus;
  186|  2.25k|    case '*':
  ------------------
  |  Branch (186:5): [True: 2.25k, False: 26.5M]
  ------------------
  187|  2.25k|      return TokenType::Star;
  188|  8.42k|    case '/':
  ------------------
  |  Branch (188:5): [True: 8.42k, False: 26.5M]
  ------------------
  189|  8.42k|      return TokenType::Slash;
  190|  2.88k|    case '&':
  ------------------
  |  Branch (190:5): [True: 2.88k, False: 26.5M]
  ------------------
  191|  2.88k|      return TokenType::Ampersand;
  192|  54.8k|    case '|':
  ------------------
  |  Branch (192:5): [True: 54.8k, False: 26.5M]
  ------------------
  193|  54.8k|      return TokenType::Pipe;
  194|  39.8k|    case '^':
  ------------------
  |  Branch (194:5): [True: 39.8k, False: 26.5M]
  ------------------
  195|  39.8k|      return TokenType::Caret;
  196|  86.9k|    case '~':
  ------------------
  |  Branch (196:5): [True: 86.9k, False: 26.5M]
  ------------------
  197|  86.9k|      return TokenType::Tilde;
  198|  67.3k|    case '!':
  ------------------
  |  Branch (198:5): [True: 67.3k, False: 26.5M]
  ------------------
  199|  67.3k|      return TokenType::Bang;
  200|   175k|    case '<':
  ------------------
  |  Branch (200:5): [True: 175k, False: 26.4M]
  ------------------
  201|   175k|      return TokenType::Less;
  202|  1.96M|    case '>':
  ------------------
  |  Branch (202:5): [True: 1.96M, False: 24.6M]
  ------------------
  203|  1.96M|      return TokenType::Greater;
  204|  65.5k|    case '=':
  ------------------
  |  Branch (204:5): [True: 65.5k, False: 26.5M]
  ------------------
  205|  65.5k|      return TokenType::Equal;
  206|  8.71k|    case '?':
  ------------------
  |  Branch (206:5): [True: 8.71k, False: 26.5M]
  ------------------
  207|  8.71k|      return TokenType::Question;
  208|  10.0k|    case ':':
  ------------------
  |  Branch (208:5): [True: 10.0k, False: 26.5M]
  ------------------
  209|  10.0k|      return TokenType::Colon;
  210|   176k|    case '(':
  ------------------
  |  Branch (210:5): [True: 176k, False: 26.4M]
  ------------------
  211|   176k|      return TokenType::LeftParen;
  212|  3.13k|    case ')':
  ------------------
  |  Branch (212:5): [True: 3.13k, False: 26.5M]
  ------------------
  213|  3.13k|      return TokenType::RightParen;
  214|   109k|    case ';':
  ------------------
  |  Branch (214:5): [True: 109k, False: 26.4M]
  ------------------
  215|   109k|      return TokenType::Semicolon;
  216|  23.6M|    default:
  ------------------
  |  Branch (216:5): [True: 23.6M, False: 2.90M]
  ------------------
  217|  23.6M|      return TokenType::Error;
  218|  26.6M|  }
  219|  26.6M|}

