Last active
August 29, 2015 13:57
-
-
Save oupo/9438174 to your computer and use it in GitHub Desktop.
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 <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()); | |
} | |
} | |
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
#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 |
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 "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