Docs GODI Archive
Projects Blog Link DB

Search GODI:


More options
File lib/felix/rtl/sm_str.h GODI Package apps-felix
 
   sm_str.h  
#line 5219 "lpsrc/sm.pak"
// str.h            see license.txt for copyright and terms of use
// a sm_string class
// the representation uses just one char*, so that a smart compiler
//   can pass the entire object as a single word
// Scott McPeak, 1995-2000  This file is public domain.

#ifndef STR_H
#define STR_H

// this should eventually be put someplace more general...
#ifndef va_copy
  #ifdef __va_copy
    #define va_copy(a,b) __va_copy(a,b)
  #else
    #define va_copy(a,b) (a)=(b)
  #endif
#endif
// MOVE THE ABOVE TO PLACE MORE GENERAL

#include "flx_rtl_config.hpp"
#include "sm_typ.h"
#include <iostream>    // std::istream, std::ostream
#include <stdarg.h>      // va_list

class Flatten;           // flatten.h
class FLX_RTL_EXTERN sm_string;

class FLX_RTL_EXTERN sm_string {
protected:     // data
  // 10/12/00: switching to never letting s be NULL
  char *s;                             // sm_string contents; never NULL
  static char * const empty;           // a global ""; should never be modified

protected:     // funcs
  void dup(char const *source);        // copies, doesn't dealloc first
  void kill();                         // dealloc if str != 0

public:        // funcs
  sm_string(sm_string const &src) { dup(src.s); }
  sm_string(char const *src) { dup(src); }
  sm_string(char const *src, int length);    // grab a subsm_string
  sm_string(int length) { s=empty; setlength(length); }
  sm_string() { s=empty; }

  ~sm_string() { kill(); }

  sm_string(Flatten&);
  void xfer(Flatten &flat);

  // simple queries
  int length() const;           // returns number of non-null chars in the sm_string; length of "" is 0
  bool isempty() const { return s[0]==0; }
  bool contains(char c) const;

  // array-like access
  char& operator[] (int i) { return s[i]; }
  char operator[] (int i) const { return s[i]; }

  // subsm_string
  sm_string subsm_string(int startIndex, int length) const;

  // conversions
  //operator char* () { return s; }      // ambiguities...
  operator char const* () const { return s; }
  char *pchar() { return s; }
  char const *pcharc() const { return s; }

  // assignment
  sm_string& operator=(sm_string const &src)
    { if (&src != this) { kill(); dup(src.s); } return *this; }
  sm_string& operator=(char const *src)
    { if (src != s) { kill(); dup(src); } return *this; }

  // allocate 'newlen' + 1 bytes (for null); initial contents is ""
  sm_string& setlength(int newlen);

  // comparison; return value has same meaning as strcmp's return value:
  //   <0   if   *this < src
  //   0    if   *this == src
  //   >0   if   *this > src
  int compareTo(sm_string const &src) const;
  int compareTo(char const *src) const;
  bool equals(char const *src) const { return compareTo(src) == 0; }

  #define MAKEOP(op)                                                             \
    bool operator op (sm_string const &src) const { return compareTo(src) op 0; }   \
    /*bool operator op (const char *src) const { return compareTo(src) op 0; }*/ \
    /* killed stuff with char* because compilers are too flaky; use compareTo */
  MAKEOP(==)  MAKEOP(!=)
  MAKEOP(>=)  MAKEOP(>)
  MAKEOP(<=)  MAKEOP(<)
  #undef MAKEOP

  // concatenation (properly handles sm_string growth)
  // uses '&' instead of '+' to avoid char* coercion problems
  sm_string operator& (sm_string const &tail) const;
  sm_string& operator&= (sm_string const &tail);

  // input/output
  friend std::istream& operator>> (std::istream &is, sm_string &obj)
    { obj.readline(is); return is; }
  friend std::ostream& operator<< (std::ostream &os, sm_string const &obj)
    { obj.write(os); return os; }

  // note: the read* functions are currently implemented in a fairly
  // inefficient manner (one char at a time)

  void readdelim(std::istream &is, char const *delim);
    // read from is until any character in delim is encountered; consumes that
    // character, but does not put it into the sm_string; if delim is null or
    // empty, reads until EOF

  void readall(std::istream &is) { readdelim(is, NULL); }
    // read all remaining chars of is into this

  void readline(std::istream &is) { readdelim(is, "\n"); }
    // read a line from input stream; consumes the \n, but doesn't put it into
    // the sm_string

  void write(std::ostream &os) const;
    // writes all stored characters (but not '\0')

  // debugging
  void selfCheck() const;
    // fail an assertion if there is a problem
};


// replace() and trimWhiteSpace() have been moved to strutil.h


// this class is specifically for appending lots of things
class FLX_RTL_EXTERN sm_stringBuilder : public sm_string {
protected:
  enum { EXTRA_SPACE = 30 };    // extra space allocated in some situations
  char *end;          // current end of the sm_string (points to the NUL character)
  int size;           // amount of space (in bytes) allocated starting at 's'

protected:
  void init(int initSize);
  void dup(char const *src);

public:
  sm_stringBuilder(int length=0);    // creates an empty sm_string
  sm_stringBuilder(char const *str);
  sm_stringBuilder(char const *str, int length);
  sm_stringBuilder(sm_string const &str) { dup((char const*)str); }
  sm_stringBuilder(sm_stringBuilder const &obj) { dup((char const*)obj); }
  ~sm_stringBuilder() {}

  sm_stringBuilder& operator= (char const *src);
  sm_stringBuilder& operator= (sm_string const &s) { return operator= ((char const*)s); }
  sm_stringBuilder& operator= (sm_stringBuilder const &s) { return operator= ((char const*)s); }

  int length() const { return end-s; }
  bool isempty() const { return length()==0; }

  sm_stringBuilder& setlength(int newlen);    // change length, forget current data

  // make sure we can store 'someLength' non-null chars; grow if necessary
  void ensure(int someLength) { if (someLength >= size) { grow(someLength); } }

  // grow the sm_string's length (retaining data); make sure it can hold at least
  // 'newMinLength' non-null chars
  void grow(int newMinLength);

  // this can be useful if you modify the sm_string contents directly..
  // it's not really the intent of this class, though
  void adjustend(char* newend);

  // make the sm_string be the empty sm_string, but don't change the
  // allocated space
  void clear() { adjustend(s); }

  // concatenation, which is the purpose of this class
  sm_stringBuilder& operator&= (char const *tail);

  // useful for appending subsm_strings or sm_strings with NUL in them
  void append(char const *tail, int length);

  // append a given number of spaces; meant for contexts where we're
  // building a multi-line sm_string; returns '*this'
  sm_stringBuilder& indent(int amt);

  // sort of a mixture of Java compositing and C++ i/o strstream
  // (need the coercion versions (like int) because otherwise gcc
  // spews mountains of f-ing useless warnings)
  sm_stringBuilder& operator << (char const *text) { return operator&=(text); }
  sm_stringBuilder& operator << (char c);
  sm_stringBuilder& operator << (unsigned char c) { return operator<<((char)c); }
  sm_stringBuilder& operator << (long i);
  sm_stringBuilder& operator << (unsigned long i);
  sm_stringBuilder& operator << (int i) { return operator<<((long)i); }
  sm_stringBuilder& operator << (unsigned i) { return operator<<((unsigned long)i); }
  sm_stringBuilder& operator << (short i) { return operator<<((long)i); }
  sm_stringBuilder& operator << (unsigned short i) { return operator<<((long)i); }
  sm_stringBuilder& operator << (double d);
  sm_stringBuilder& operator << (void *ptr);     // inserts address in hex
  #ifndef LACKS_BOOL
    sm_stringBuilder& operator << (bool b) { return operator<<((long)b); }
  #endif // LACKS_BOOL

  // useful in places where long << expressions make it hard to
  // know when arguments will be evaluated, but order does matter
  typedef sm_stringBuilder& (*Manipulator)(sm_stringBuilder &sb);
  sm_stringBuilder& operator<< (Manipulator manip);

  // stream readers
  friend std::istream& operator>> (std::istream &is, sm_stringBuilder &sb)
    { sb.readline(is); return is; }
  void readall(std::istream &is) { readdelim(is, NULL); }
  void readline(std::istream &is) { readdelim(is, "\n"); }

  void readdelim(std::istream &is, char const *delim);

  // an experiment: hex formatting (something I've sometimes done by resorting
  // to sprintf in the past)
  class Hex {
  public:
    unsigned long value;

    Hex(unsigned long v) : value(v) {}
    Hex(Hex const &obj) : value(obj.value) {}
  };
  sm_stringBuilder& operator<< (Hex const &h);
  #define SBHex sm_stringBuilder::Hex
};


// the real strength of this entire module: construct sm_strings in-place
// using the same syntax as C++ istd::ostreams.  e.g.:
//   puts(sm_stringb("x=" << x << ", y=" << y));
#define sm_stringb(expr) (sm_stringBuilder() << expr)

// experimenting with dropping the () in favor of <<
// (the "c" can be interpreted as "constructor", or maybe just
// the successor to "b" above)
#define sm_stringc sm_stringBuilder()


// experimenting with using toString as a general method for datatypes
sm_string toString(int i);
sm_string toString(unsigned i);
sm_string toString(char c);
sm_string toString(long i);
sm_string toString(char const *str);
sm_string toString(float f);


// printf-like construction of a sm_string; often very convenient, since
// you can use any of the formatting characters (like %X) that your
// libc's sprintf knows about
sm_string sm_stringf(char const *format, ...);
sm_string vsm_stringf(char const *format, va_list args);


#endif // STR_H

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml