Skip to content

Instantly share code, notes, and snippets.

@oupo
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oupo/9438174 to your computer and use it in GitHub Desktop.
Save oupo/9438174 to your computer and use it in GitHub Desktop.
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <algorithm>
#include "litestring.h"
static int firstCapa(int len) {
return len == 0 ? 64 : (len + 63) & ~63;
}
static int increaseCapa(int capa, int necessary) {
int newCapa = capa;
while (newCapa < necessary) {
newCapa *= 2;
}
return newCapa;
}
LiteStringBody::LiteStringBody(char *ptr, int length, int capa, LiteStringBody *shared)
: ptr_(ptr), length_(length), capa_(capa), refCount_(0), shared_(shared) {
#ifdef LITESTRING_DEBUG
printf("new litestring:%.*s\n", length, ptr);
#endif
}
LiteString LiteString::create(const char *str) {
int len = strlen(str);
int capa = firstCapa(len + 1);
char *ptr = (char *)malloc(capa);
strcpy(ptr, str);
return LiteString(new LiteStringBody(ptr, len, capa, NULL));
}
LiteString LiteString::createShared(const char *str) {
return LiteString(new LiteStringBody((char *)str, strlen(str), 0, (LiteStringBody *)1));
}
LiteString LiteString::concat(LiteString str1, LiteString str2) {
LiteStringBody *a = str1.body_, *b = str2.body_;
if (a->length_ == 0) return LiteString(b);
if (b->length_ == 0) return LiteString(a);
int len = a->length_ + b->length_;
if (!a->shared_ && len + 1 <= a->capa_) {
memcpy(a->ptr_ + a->length_, b->ptr_, b->length_);
a->ptr_[len] = '\0';
LiteStringBody *c = new LiteStringBody(a->ptr_, len, a->capa_, NULL);
a->shared_ = c;
return LiteString(c).addRef(); // a->shared_からの参照
} else {
return concatWithNewBuffer(str1, str2);
}
}
void LiteString::concatAssign(LiteString *pstr1, LiteString str2) {
LiteStringBody *a = pstr1->body_, *b = str2.body_;
if (a->length_ == 0) {
ASSIGN(*pstr1, str2);
return;
}
if (b->length_ == 0) return;
int len = a->length_ + b->length_;
if (!a->shared_ && len + 1 <= a->capa_) {
memcpy(a->ptr_ + a->length_, b->ptr_, b->length_);
a->ptr_[len] = '\0';
if (a->refCount_ == 1) {
// pstrからしか参照されていない場合は、新しいオブジェクトを作らず再利用
a->length_ = len;
} else {
LiteStringBody *c = new LiteStringBody(a->ptr_, len, a->capa_, NULL);
a->shared_ = c;
ASSIGN(*pstr1, LiteString(c).addRef());
}
} else {
ASSIGN(*pstr1, concatWithNewBuffer(*pstr1, str2));
}
}
LiteString LiteString::concatWithNewBuffer(LiteString str1, LiteString str2) {
LiteStringBody *a = str1.body_, *b = str2.body_;
int len = a->length_ + b->length_;
int capa;
if (a->shared_) {
capa = firstCapa(len + 1);
} else {
capa = a->capa_ = increaseCapa(a->capa_, len + 1);
}
char *ptr = (char *)malloc(capa);
memcpy(ptr, a->ptr_, a->length_);
memcpy(ptr + a->length_, b->ptr_, b->length_);
ptr[len] = '\0';
return LiteString(new LiteStringBody(ptr, len, capa, NULL));
}
LiteString LiteString::substr(int index, int length) {
index = std::min(index, this->length());
length = std::min(length, this->length() - index);
this->addRef();
return LiteString(new LiteStringBody(body_->ptr_ + index, length, 0, body_));
}
void LiteString::release() {
if (null()) return;
assert(body_->refCount_ >= 0);
if ((--body_->refCount_) == 0) {
#ifdef LITESTRING_DEBUG
printf("delete litestring:%.*s\n", length(), ptr());
#endif
if (body_->shared_ > (LiteStringBody *)1) {
LiteString(body_->shared_).release();
} else if (body_->shared_ == 0) {
free(body_->ptr_);
}
delete body_;
} else {
printf("release litestring:%d %.*s\n", body_->refCount_, length(), ptr());
}
}
#ifndef __litestring_h
#define __litestring_h
#ifdef LITESTRING_DEBUG
#include "stdio.h"
#endif
class LiteString;
class LiteStringBody {
friend class LiteString;
private:
char *ptr_;
int length_;
int capa_;
int refCount_;
LiteStringBody *shared_;
LiteStringBody(char *ptr, int length, int capa, LiteStringBody *shared);
LiteStringBody(const LiteStringBody&);
void operator=(const LiteStringBody&);
};
class LiteString {
public:
LiteString() : body_(0) {}
static LiteString create(const char *str);
static LiteString createShared(const char *str);
static LiteString concat(LiteString a, LiteString b);
static void concatAssign(LiteString *a, LiteString b);
LiteString substr(int index, int length);
int length() { return body_->length_; }
const char *ptr() { return body_->ptr_; }
LiteString addRef() {
if (body_) {
body_->refCount_++;
#ifdef LITESTRING_DEBUG
printf("litestring ref:%d %.*s\n", body_->refCount_, body_->length_, body_->ptr_);
#endif
}
return *this;
}
bool null() { return body_ == 0; }
void release();
static void ASSIGN(LiteString &x, LiteString a) {
x.release();
a.addRef();
x = a;
}
private:
static LiteString concatWithNewBuffer(LiteString a, LiteString b);
LiteString(LiteStringBody *body): body_(body) {}
LiteStringBody *body_;
};
#endif
#include "litestring.h"
#include <map>
#include <string>
#include <fstream>
#include <iostream>
#include <regex>
#include <conio.h>
void tell_undefined(std::string name) { std::cout << name << " is undefined." << std::endl; }
int main() {
std::string line;
std::map<std::string, LiteString> vars;
std::vector<std::string> literals;
while (std::getline(std::cin, line)) {
std::smatch mr;
if (std::regex_match(line, mr, std::regex("(\\w+)=\"(.*)\""))) {
std::string name = mr[1];
std::string val = mr[2];
LiteString::ASSIGN(vars[name], LiteString::create(val.c_str()));
} else if (std::regex_match(line, mr, std::regex("(\\w+)=:(.*)"))) {
std::string name = mr[1];
std::string val = mr[2];
literals.push_back(val);
LiteString::ASSIGN(vars[name], LiteString::createShared(literals.back().c_str()));
} else if (std::regex_match(line, mr, std::regex("(\\w+)=(\\w+)"))) {
std::string name1 = mr[1];
std::string name2 = mr[2];
if (vars[name2].null()) tell_undefined(name2);
else {
LiteString::ASSIGN(vars[name1], vars[name2]);
}
} else if (std::regex_match(line, mr, std::regex("(\\w+)=(\\w+)\\+(\\w+)"))) {
std::string name1 = mr[1];
std::string name2 = mr[2];
std::string name3 = mr[3];
if (vars[name2].null()) tell_undefined(name2);
else if (vars[name3].null()) tell_undefined(name3);
else {
LiteString::ASSIGN(vars[name1], LiteString::concat(vars[name2], vars[name3]));
}
} else if (std::regex_match(line, mr, std::regex("(\\w+)\\+=(\\w+)"))) {
std::string name1 = mr[1];
std::string name2 = mr[2];
if (vars[name2].null()) tell_undefined(name2);
else {
LiteString::concatAssign(&vars[name1], vars[name2]);
}
} else if (std::regex_match(line, mr, std::regex("(\\w+)=sub\\((\\w+),(\\d+),(\\d+)\\)"))) {
std::string name1 = mr[1];
std::string name2 = mr[2];
int index = std::stoi(mr[3]);
int length = std::stoi(mr[4]);
if (vars[name2].null()) tell_undefined(name2);
else {
LiteString::ASSIGN(vars[name1], vars[name2].substr(index, length));
}
} else if (std::regex_match(line, mr, std::regex("del (\\w+)"))) {
std::string name1 = mr[1];
LiteString::ASSIGN(vars[name1], LiteString());
} else {
std::cout << "parse error" << std::endl;
}
}
for (auto x : vars) {
x.second.release();
}
std::cout << "finished." << std::endl;
_getch();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment