text: #include "HalideRuntime.h"
  
  extern "C" {
  
  WEAK char *halide_string_to_string(char *dst, char *end, const char *arg) {
      if (dst >= end) return dst;
      while (1) {
          if (dst == end) {
              dst[-1] = 0;
              return dst;
          }
          *dst = *arg;
          if (*dst == 0) {
              return dst;
          }
          dst++;
          arg++;
      }
  }
  
  WEAK char *halide_uint64_to_string(char *dst, char *end, uint64_t arg, int min_digits) {
      // 32 is more than enough chars to contain any 64-bit int.
      char buf[32];
      buf[31] = 0;
      char *digits = buf+30;
  
      for (int i = 0; i < min_digits || arg; i++) {
          uint64_t top = arg / 10;
          uint64_t bottom = arg - top * 10;
          *digits = bottom + '0';
          digits--;
          arg = top;
      }
      digits++;
  
      return halide_string_to_string(dst, end, digits);
  }
  
  WEAK char *halide_int64_to_string(char *dst, char *end, int64_t arg, int min_digits) {
      if (arg < 0 && dst < end) {
          *dst++ = '-';
          arg = -arg;
      }
      return halide_uint64_to_string(dst, end, arg, min_digits);
  }
  
  WEAK char *halide_double_to_string(char *dst, char *end, double arg, int scientific) {
      uint64_t bits = 0;
      memcpy(&bits, &arg, sizeof(double));
  
      uint64_t one = 1;
      uint64_t mantissa = bits & ((one << 52) - 1);
      int biased_exponent = (bits >> 52) & ((1 << 11) - 1);
      int negative = (bits >> 63);
  
      // Handle special values
      if (biased_exponent == 2047) {
          if (mantissa) {
              if (negative) {
                  return halide_string_to_string(dst, end, "-nan");
              } else {
                  return halide_string_to_string(dst, end, "nan");
              }
          } else {
              if (negative) {
                  return halide_string_to_string(dst, end, "-inf");
              } else {
                  return halide_string_to_string(dst, end, "inf");
              }
          }
      } else if (biased_exponent == 0 && mantissa == 0) {
          if (scientific) {
              if (negative) {
                  return halide_string_to_string(dst, end, "-0.000000e+00");
              } else {
                  return halide_string_to_string(dst, end, "0.000000e+00");
              }
          } else {
              if (negative) {
                  return halide_string_to_string(dst, end, "-0.000000");
              } else {
                  return halide_string_to_string(dst, end, "0.000000");
              }
          }
      }
  
      if (negative) {
          dst = halide_string_to_string(dst, end, "-");
          arg = -arg;
      }
  
  
      // The desired number of decimal places.
      const int decimal_places = 6;
  
      // 10 ^ decimal places
      const uint64_t scale = 1000000;
  
      // The number of bits in the mantissa of an IEEE double.
      const int mantissa_bits = 52;
  
      if (scientific) {
  
          // Compute base 10 exponent and normalize the number to within [1, 10)
          int exponent_base_10 = 0;
          while (arg < 1) {
              arg *= 10;
              exponent_base_10--;
          }
  
          while (arg >= 10) {
              arg /= 10;
              exponent_base_10++;
          }
  
          // Convert to fixed-point;
          uint64_t fixed = (uint64_t)(arg * scale + 0.5);
          uint64_t top_digit = fixed / scale;
          uint64_t other_digits = fixed - top_digit * scale;
  
          dst = halide_int64_to_string(dst, end, top_digit, 1);
          dst = halide_string_to_string(dst, end, ".");
          dst = halide_int64_to_string(dst, end, other_digits, decimal_places);
  
          if (exponent_base_10 >= 0) {
              dst = halide_string_to_string(dst, end, "e+");
          } else {
              dst = halide_string_to_string(dst, end, "e-");
              exponent_base_10 = -exponent_base_10;
          }
          dst = halide_int64_to_string(dst, end, exponent_base_10, 2);
  
      } else {
          // Denormals flush to zero in non-scientific mode. We've
          // already printed the sign.
          if (biased_exponent == 0) {
              return halide_double_to_string(dst, end, 0.0, false);
          }
  
          // Express it as an integer times a power of two.
          uint64_t n = mantissa + (one << mantissa_bits);
          int exponent = biased_exponent - 1023 - mantissa_bits;
  
          // Break it into integer and fractional parts.
          uint64_t integer_part = n;
          int integer_exponent = exponent;
  
          uint64_t fractional_part = 0;
          if (exponent < 0) {
              // There is a fractional component.
  
              double f;
              if (exponent < -mantissa_bits) {
                  // There's no integer component.
                  integer_part = 0;
                  f = n;
              } else {
                  integer_part >>= (-exponent);
                  f = n - (integer_part << (-exponent));
              }
              integer_exponent = 0;
  
              // Construct 10^decimal_places * 2^exponent exactly
              // (recall exponent is negative).
              union {
                  uint64_t bits;
                  double as_double;
              } multiplier;
              multiplier.as_double = scale;
              multiplier.bits += (uint64_t)(exponent) << mantissa_bits;
  
              // Use it to get the first 6 digits of the fractional part
              // into the integer part.
              f = f * multiplier.as_double + 0.5;
  
              // Round-to-even, to match glibc.
              fractional_part = (uint64_t)f;
              if (fractional_part == f &&
                  (fractional_part & 1)) {
                  fractional_part--;
              }
  
              // If we rounded the fractional part up to the scale
              // factor, we'd better reattribute it to the integer part.
              if (fractional_part == scale) {
                  fractional_part = 0;
                  integer_part++;
              }
          }
  
          // The number is now:
          // integer_part * 2^integer_exponent + fractional_part * 2^exponent.
  
          // Convert integer_part to decimal, then repeatedly double it.
  
          // The largest double is 310 digits long.
          char buf[512];
          // Start 32 chars before the end of the scratch buffer and work
          // backwards to allow space for carried digits.
          char *int_part_ptr = buf + 512 - 32;
          char *buf_end = halide_int64_to_string(int_part_ptr, buf + 512, integer_part, 1);
          for (int i = 0; i < integer_exponent; i++) {
              // Double each digit, with ripple carry.
              int carry = 0;
              for (char *p = buf_end - 1; p != int_part_ptr - 1; p--) {
                  char old_digit = *p - '0';
                  char new_digit = old_digit * 2 + carry;
                  if (new_digit > 9) {
                      new_digit -= 10;
                      carry = 1;
                  } else {
                      carry = 0;
                  }
                  *p = new_digit + '0';
              }
              if (carry) {
                  // There was a carry in the last digit. Add a new '1'
                  // at the start.
                  int_part_ptr--;
                  *int_part_ptr = '1';
              }
          }
          dst = halide_string_to_string(dst, end, int_part_ptr);
          dst = halide_string_to_string(dst, end, ".");
          dst = halide_int64_to_string(dst, end, fractional_part, decimal_places);
      }
  
      return dst;
  }
  
  WEAK char *halide_pointer_to_string(char *dst, char *end, const void *arg) {
      const char *hex_digits = "0123456789abcdef";
      char buf[20] = {0};
      char *buf_ptr = buf+18;
      uint64_t bits = (uint64_t)arg;
      for (int i = 0; i < 16; i++) {
          *buf_ptr-- = hex_digits[bits & 15];
          bits >>= 4;
          if (!bits) break;
      }
      *buf_ptr-- = 'x';
      *buf_ptr = '0';
      return halide_string_to_string(dst, end, buf_ptr);
  }
  
  WEAK char *halide_type_to_string(char *dst, char *end, const halide_type_t *t) {
      const char *code_name = NULL;
      switch(t->code) {
      case halide_type_int:
          code_name = "int";
          break;
      case halide_type_uint:
          code_name = "uint";
          break;
      case halide_type_float:
          code_name = "float";
          break;
      case halide_type_handle:
          code_name = "handle";
          break;
      default:
          code_name = "bad_type_code";
          break;
      }
      dst = halide_string_to_string(dst, end, code_name);
      dst = halide_uint64_to_string(dst, end, t->bits, 1);
      if (t->lanes != 1) {
          dst = halide_string_to_string(dst, end, "x");
          dst = halide_uint64_to_string(dst, end, t->lanes, 1);
      }
      return dst;
  }
  
  WEAK char *halide_buffer_to_string(char *dst, char *end, const halide_buffer_t *buf) {
      if (buf == NULL) {
          return halide_string_to_string(dst, end, "NULL");
      }
      dst = halide_string_to_string(dst, end, "buffer(");
      dst = halide_uint64_to_string(dst, end, buf->device, 1);
      dst = halide_string_to_string(dst, end, ", ");
      dst = halide_pointer_to_string(dst, end, buf->device_interface);
      dst = halide_string_to_string(dst, end, ", ");
      dst = halide_pointer_to_string(dst, end, buf->host);
      dst = halide_string_to_string(dst, end, ", ");
      dst = halide_uint64_to_string(dst, end, buf->flags, 1);
      dst = halide_string_to_string(dst, end, ", ");
      dst = halide_type_to_string(dst, end, &(buf->type));
      for (int i = 0; i < buf->dimensions; i++) {
          dst = halide_string_to_string(dst, end, ", {");
          dst = halide_int64_to_string(dst, end, buf->dim[i].min, 1);
          dst = halide_string_to_string(dst, end, ", ");
          dst = halide_int64_to_string(dst, end, buf->dim[i].extent, 1);
          dst = halide_string_to_string(dst, end, ", ");
          dst = halide_int64_to_string(dst, end, buf->dim[i].stride, 1);
          dst = halide_string_to_string(dst, end, "}");
      }
      dst = halide_string_to_string(dst, end, ")");
      return dst;
  }
  
  }
  