std::shared_ptr unity_sarray::lazy_astype()

in src/core/storage/sframe_interface/unity_sarray.cpp [1372:1494]


std::shared_ptr<unity_sarray_base> unity_sarray::lazy_astype(flex_type_enum dtype,
                                                             bool undefined_on_failure) {
  log_func_entry();

  flex_type_enum current_type = this->dtype();
  // Special path for converting image sarray to vector type.
  if (current_type == flex_type_enum::IMAGE &&
      dtype == flex_type_enum::VECTOR) {
      return image_util::image_sarray_to_vector_sarray(
          std::static_pointer_cast<unity_sarray>(shared_from_this()),
          undefined_on_failure);
  }

  // Special path for converting strings to image
  if (current_type == flex_type_enum::STRING &&
      dtype == flex_type_enum::IMAGE) {
    return transform_lambda([=](const flexible_type& f)->flexible_type {
                                  try {
                                    return image_util::load_image(f.to<flex_string>(), "");
                                  } catch (...) {
                                    if (undefined_on_failure) return FLEX_UNDEFINED;
                                    else throw;
                                  }
                                },
                                dtype,
                                true /*skip undefined*/,
                                0 /*random seed*/);
  };

  // if no changes. just keep the identity function
  if (dtype == current_type) {
    return std::static_pointer_cast<unity_sarray>(shared_from_this());
  }

  if(! (flex_type_is_convertible(current_type, dtype) ||
        (current_type == flex_type_enum::STRING && dtype == flex_type_enum::INTEGER) ||
        (current_type == flex_type_enum::STRING && dtype == flex_type_enum::FLOAT) ||
        (current_type == flex_type_enum::STRING && dtype == flex_type_enum::VECTOR) ||
        (current_type == flex_type_enum::STRING && dtype == flex_type_enum::LIST) ||
        (current_type == flex_type_enum::STRING && dtype == flex_type_enum::DICT) ||
        (current_type == flex_type_enum::LIST && dtype == flex_type_enum::VECTOR)
       )) {
    log_and_throw("Not able to cast to given type");
  }


  // The assigment operator takes care of casting
  if (current_type == flex_type_enum::STRING) {
    flexible_type_parser parser;
    // we need to treat strings with special care
    // we need to perform a lexical cast
    auto transform_fn = [dtype,undefined_on_failure,parser]
        (const flexible_type& f)mutable ->flexible_type {
      if (f.get_type() == flex_type_enum::UNDEFINED) return f;
      flexible_type ret;
      try {
        if (dtype == flex_type_enum::INTEGER) {
          ret = f.to<flex_int>();
        } else if (dtype == flex_type_enum::FLOAT) {
          ret = f.to<flex_float>();
        } else if (dtype == flex_type_enum::VECTOR) {
          bool success;
          const std::string& val = f.get<flex_string>();
          const char* c = val.c_str();
          std::tie(ret, success) = parser.vector_parse(&c, val.length());
          if (!success) {
            if (undefined_on_failure) ret = FLEX_UNDEFINED;
            else log_and_throw("Cannot convert to array");
          }
        } else if (dtype == flex_type_enum::LIST) {
          bool success;
          const std::string& val = f.get<flex_string>();
          const char* c = val.c_str();
          std::tie(ret, success) = parser.recursive_parse(&c, val.length());
          if (!success) {
            if (undefined_on_failure) ret = FLEX_UNDEFINED;
            else log_and_throw("Cannot convert to list");
          }
        } else if (dtype == flex_type_enum::DICT) {
          bool success;
          const std::string& val = f.get<flex_string>();
          const char* c = val.c_str();
          std::tie(ret, success) = parser.dict_parse(&c, val.length());
          if (!success) {
            if (undefined_on_failure) ret = FLEX_UNDEFINED;
            else log_and_throw("Cannot convert to dict");
          }
        }
      } catch(const std::string& s) {
        if (undefined_on_failure) ret = FLEX_UNDEFINED;
        else log_and_throw("Unable to interpret value of \"" + f.get<flex_string>()
                           + "\" as a " + flex_type_enum_to_name(dtype) + ".");
      } catch(const std::exception& s) {
        if (undefined_on_failure) ret = FLEX_UNDEFINED;
        else log_and_throw("Unable to interpret value of \"" + f.get<flex_string>()
                           + "\" as a " + flex_type_enum_to_name(dtype) + ".");
      }
      return ret;
    };

    auto ret = transform_lambda(transform_fn,
                                dtype,
                                true /*skip undefined*/,
                                0 /*random seed*/);
    return ret;

  } else {
    auto ret = transform_lambda([dtype, undefined_on_failure](const flexible_type& f)->flexible_type {
                                  flexible_type ret(dtype);
                                  try {
                                    ret.soft_assign(f);
                                  } catch (...) {
                                    if (undefined_on_failure) return FLEX_UNDEFINED;
                                    else throw;
                                  }
                                  return ret;
                                },
                                dtype,
                                true /*skip undefined*/,
                                0 /*random seed*/);
    return ret;
  }
}