text: #include "shared_feature_merger.h"
  #include "cb.h"
  #include "example.h"
  #include "label_dictionary.h"
  #include "learner.h"
  #include "options.h"
  #include "parse_args.h"
  #include "vw.h"
  
  #include <iterator>
  using namespace std;
  
  namespace VW
  {
  namespace shared_feature_merger
  {
  static const std::vector<std::string> option_strings = {
      "csoaa_ldf", "wap_ldf", "cb_adf", "explore_eval", "cbify_ldf", "cb_explore_adf", "warm_cb"};
  
  bool use_reduction(config::options_i& options)
  {
    for (const auto& opt : option_strings)
    {
      if (options.was_supplied(opt))
        return true;
    }
    return false;
  }
  
  struct sfm_data {};
  
  template <bool is_learn>
  void predict_or_learn(sfm_data& , LEARNER::multi_learner& base, multi_ex& ec_seq)
  {
    if (ec_seq.size() == 0)
      THROW("cb_adf: At least one action must be provided for an example to be valid.");
  
    multi_ex::value_type shared_example = nullptr;
  
    const bool has_example_header = CB::ec_is_example_header(*ec_seq[0]);
    if (has_example_header)
    {
      shared_example = ec_seq[0];
      ec_seq.erase(ec_seq.begin());
      // merge sequences
      for (auto & example : ec_seq) LabelDict::add_example_namespaces_from_example(*example, *shared_example);
      swap(ec_seq[0]->pred, shared_example->pred);
    }
    if (ec_seq.size() == 0)
      return;
    if (is_learn)
      base.learn(ec_seq);
    else
      base.predict(ec_seq);
  
    if (has_example_header)
    {
      for (auto& example : ec_seq) LabelDict::del_example_namespaces_from_example(*example, *shared_example);
      swap(shared_example->pred, ec_seq[0]->pred);
      ec_seq.insert(ec_seq.begin(), shared_example);
    }
  }
  
  LEARNER::base_learner* shared_feature_merger_setup(config::options_i& options, vw& all)
  {
    if (!use_reduction(options))
      return nullptr;
  
    auto data = scoped_calloc_or_throw<sfm_data>();
  
    auto* base = LEARNER::as_multiline(setup_base(options, all));
    auto& learner = LEARNER::init_learner(data, base, predict_or_learn<true>, predict_or_learn<false>);
  
    // TODO: Incorrect feature numbers will be reported without merging the example namespaces from the
    //       shared example in a finish_example function. However, its too expensive to perform the full operation.
  
    return LEARNER::make_base(learner);
  }
  
  }  // namespace shared_feature_merger
  
  }  // namespace VW
  