// CSE 333 Lecture 12 demo: Str.cc

// Implementation of a simple string class.

#include <cstring>
#include <iostream>
#include "Str.h"

using namespace std;

// Print trace messages with object addresses to show when functions get called.
#define TRACE(what)  cout << "- Str::" what << " called on " << this << endl

// constructors

Str::Str() {
  TRACE("default constructor");
  // allocate empty string
  st_ = new char[1];
  st_[0] = '\0';
}

Str::Str(const char *s) {
  TRACE("c-string constructor");
  int len = strlen(s);
  st_ = new char[len+1];
  strcpy(st_, s);
}

Str::Str(const Str &s) {
  TRACE("copy constructor");
  int len = strlen(s.st_);
  st_ = new char[len+1];
  strcpy(st_, s.st_);
}

// destructor
Str::~Str() {
  TRACE("destructor");
  delete [] st_;
}

// operations

int Str::length() const {
  TRACE("length");
  return strlen(st_);
}

char * Str::c_str() const {
  TRACE("c_str");
  char * result = new char[strlen(st_)+1];
  strcpy(result, st_);
  return result;
}


void Str::append(const Str &s) {
  TRACE("append");
  char *newst = new char[strlen(st_) + strlen(s.st_) + 1];
  strcpy(newst, st_);
  strcat(newst, s.st_);
  delete [] st_;
  st_ = newst;
}

Str & Str::operator=(const Str &s) {
  TRACE("assignment");
  // do nothing if trying to assign a string to itself
  if (this == &s) {
    return *this;
  }

  // Replace string array with one of correct size
  // (Note: this is where the self-assignment test _really_ matters)
  // (Note: a better implementation would re-use the existing array
  //  if it's long enough, but not too long)
  delete [] st_;
  st_ = new char[strlen(s.st_)+1];

  // copy characters and return
  strcpy(st_, s.st_);
  return *this;
}

// stream output
// (Note: not a member function of Str.  This is an overloaded global
// function that is a friend of Str so it can access private data)
ostream &operator<<(ostream &out, const Str &s) {
  out << s.st_;
  return out;
}