Created
April 1, 2012 23:57
-
-
Save pareis/2279561 to your computer and use it in GitHub Desktop.
Java programming in C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <sstream> | |
#include <assert.h> | |
#include <vector> | |
size_t globalRefCount = 0; | |
class Object; | |
class String; | |
std::ostream &operator<<(std::ostream&, Object&); | |
std::ostream &operator<<(std::ostream &, const String&); | |
class Object { | |
protected: | |
struct Impl { | |
size_t _refCount; | |
Impl() : _refCount(0) {} | |
virtual ~Impl() {} | |
} *data; | |
inline void retain() { | |
if(data) { | |
data->_refCount++; | |
globalRefCount++; | |
} | |
} | |
inline void release() { | |
if(data) { | |
data->_refCount--; | |
globalRefCount--; | |
if(data->_refCount == 0) { | |
delete data; | |
data = 0; | |
} | |
} | |
} | |
Object(): data(new Impl) { | |
retain(); | |
} | |
Object(Impl *imp) : data(imp) { | |
retain(); | |
} | |
Object(const Object& other): data(0) { | |
operator=(other); | |
} | |
public: | |
virtual ~Object() { | |
release(); | |
} | |
virtual const char *type() const { return "Object"; } | |
void operator=(const Object& other) { | |
if(data!=other.data) { | |
release(); | |
data = other.data; | |
retain(); | |
} | |
} | |
// make a heap clone of this object for usage in containers | |
virtual Object *clone() const { | |
return new Object(*this); | |
} | |
virtual String toString() const; | |
}; | |
class String : public Object { | |
protected: | |
struct Impl: public Object::Impl { | |
std::string str; | |
}; | |
public: | |
String(): Object(new Impl) {} | |
String(const char *s): Object(new Impl) { | |
static_cast<Impl*>(data)->str = s; | |
} | |
String(const String &other): Object(other) {} | |
String operator+(const String& s) const { | |
String result; | |
static_cast<Impl*>(result.data)->str = static_cast<Impl*>(data)->str; | |
static_cast<Impl*>(result.data)->str += static_cast<Impl*>(s.data)->str; | |
return result; | |
} | |
String operator+(const Object& s) const { | |
String result; | |
static_cast<Impl*>(result.data)->str = static_cast<Impl*>(data)->str; | |
static_cast<Impl*>(result.data)->str += static_cast<Impl*>(s.toString().data)->str; | |
return result; | |
} | |
String operator+(long l) const { | |
std::ostringstream oss; | |
oss << static_cast<Impl*>(data)->str << l; | |
String result; | |
static_cast<Impl*>(result.data)->str = oss.str(); | |
return result; | |
} | |
const char *c_str() const { | |
return static_cast<Impl*>(data)->str.c_str(); | |
} | |
bool operator==(const String &other) const { | |
return static_cast<Impl*>(data)->str == static_cast<Impl*>(other.data)->str; | |
} | |
// must have's | |
const char *type() const { return "String"; } | |
Object *clone() const { return new String(*this); } | |
String toString() const { | |
return *this; | |
} | |
}; | |
std::ostream &operator<<(std::ostream &os, const String& s) { | |
os << s.c_str(); | |
return os; | |
} | |
String Object::toString() const { | |
std::ostringstream os; | |
os << this->type() << "@" << (void *)this << "[" << (data ? data->_refCount : 0) << "]"; | |
return String(os.str().c_str()); | |
} | |
std::ostream &operator<<(std::ostream &os, Object& o) { | |
os << o.toString().c_str(); | |
return os; | |
} | |
class ClassCastException: public Object { | |
struct Impl: public Object::Impl { | |
String message; | |
}; | |
public: | |
ClassCastException() : Object(new Impl) {} | |
ClassCastException(const String& msg) : Object(new Impl) { | |
static_cast<Impl*>(data)->message = msg; | |
} | |
const char *type() const { return "ClassCastException"; } | |
Object *clone() const { return new ClassCastException(*this); } | |
String message() const { | |
return static_cast<Impl*>(data)->message; | |
} | |
String toString() const { | |
return message(); | |
} | |
}; | |
class ArrayList: public Object { | |
struct Impl: public Object::Impl { | |
std::vector<Object*> _data; | |
}; | |
public: | |
ArrayList(): Object(new Impl) {} | |
~ArrayList() { | |
Impl *self = static_cast<Impl*>(data); | |
for (std::vector<Object*>::iterator it = self->_data.begin(); it!=self->_data.end(); it++) { | |
delete *it; | |
} | |
} | |
void add(const Object& element) { | |
static_cast<Impl*>(data)->_data.push_back(element.clone()); | |
} | |
size_t size() const { | |
return static_cast<Impl*>(data)->_data.size(); | |
} | |
Object &at(size_t index) const { | |
return *static_cast<Impl*>(data)->_data.at(index); | |
} | |
template<class T> const T &at(size_t index) const { | |
Object *o = static_cast<Impl*>(data)->_data.at(index); | |
T *t = dynamic_cast<T*>(o); | |
if(t) return *t; | |
throw ClassCastException(o->type()); | |
} | |
const char *type() const { return "ArrayList"; } | |
Object *clone() const { return new ArrayList(*this); } | |
String toString() const { | |
std::ostringstream oss; | |
oss << Object::toString() << "("; | |
for (size_t i = 0; i<size(); i++) { | |
oss << at(i).toString(); | |
if(i+1<size()) { | |
oss << ","; | |
} | |
} | |
oss << ")"; | |
return oss.str().c_str(); | |
} | |
}; | |
class OutputStream: public Object { | |
struct Impl: public Object::Impl { | |
std::ostream &stream; | |
Impl(std::ostream &os): stream(os) {} | |
}; | |
OutputStream() {} | |
public: | |
OutputStream(std::ostream& os): Object(new Impl(os)) {} | |
OutputStream(const OutputStream &other): Object(other) {} | |
void println(const Object &object) { | |
static_cast<Impl*>(data)->stream << object.toString() << std::endl; | |
} | |
const char *type() const { return "OutputStream"; } | |
Object *clone() const { return new OutputStream(*this); } | |
}; | |
struct system { | |
OutputStream out; | |
system(): out(std::cout) {} | |
}; | |
struct system System; | |
int main (int argc, const char * argv[]) { | |
assert(globalRefCount==1); // 1 is for System.out | |
{ | |
String s; | |
assert(globalRefCount==2); | |
} | |
assert(globalRefCount==1); | |
{ | |
String s = "Connecting..."; | |
System.out.println(String("s = ") + s); | |
String dots = "the dots"; | |
String t = s + " " + dots + "."; | |
System.out.println(String("t = ") + t); | |
ArrayList l; | |
l.add(s); | |
assert(l.size() == 1); | |
assert(globalRefCount==6); | |
l.add(t); | |
l.add(ArrayList()); | |
System.out.println(String("l = ") + l); | |
assert(globalRefCount==8); | |
try { | |
System.out.println(String("l[0] as String = ") + l.at<String>(0)); // ok | |
System.out.println(String("l[1] as String = ") + l.at<String>(1)); // ok | |
System.out.println(String("l[2] as String = ") + l.at<String>(2)); // this throws! | |
assert(false); | |
} catch(ClassCastException e) { | |
System.out.println(String("ClassCastException: ") + e); | |
l.add(e); | |
} | |
// adding to the list in other scope will keep the object valid | |
{ | |
String other = "Created in other scope"; | |
l.add(other); | |
} | |
System.out.println(String("l[3] as String = ") + l.at(3)); | |
assert(l.size()==5); | |
assert(l.at<String>(4) == "Created in other scope"); | |
System.out.println(String("l = ") + l); | |
} | |
assert(globalRefCount == 1); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment