use new vector impl

This commit is contained in:
blueloveTH 2024-06-01 18:18:38 +08:00
parent ac82f6f33f
commit a59592b799
25 changed files with 282 additions and 201 deletions

View File

@ -1,5 +1,5 @@
SRC=$(find src/ -name "*.cpp") SRC=$(find src/ -name "*.cpp")
FLAGS="-std=c++17 -O2 -stdlib=libc++ -Iinclude -frtti -Wfatal-errors -g" FLAGS="-std=c++17 -Og -stdlib=libc++ -Iinclude -frtti -Wfatal-errors -g"
clang++ $FLAGS -o main src2/main.cpp $SRC clang++ $FLAGS -o main src2/main.cpp $SRC

View File

@ -70,17 +70,17 @@ struct CodeObject {
std::shared_ptr<SourceData> src; std::shared_ptr<SourceData> src;
Str name; Str name;
std::vector<Bytecode> codes; vector<Bytecode> codes;
std::vector<LineInfo> lines; vector<LineInfo> lines;
small_vector_2<PyVar, 8> consts; // constants small_vector_2<PyVar, 8> consts; // constants
small_vector_2<StrName, 8> varnames; // local variables small_vector_2<StrName, 8> varnames; // local variables
int nlocals; // varnames.size() int nlocals; // varnames.size()
NameDictInt varnames_inv; NameDictInt varnames_inv;
std::vector<CodeBlock> blocks; vector<CodeBlock> blocks;
NameDictInt labels; NameDictInt labels;
std::vector<FuncDecl_> func_decls; vector<FuncDecl_> func_decls;
int start_line; int start_line;
int end_line; int end_line;

View File

@ -5,7 +5,6 @@
#include <ctime> #include <ctime>
#include <stdexcept> #include <stdexcept>
#include <vector>
#include <string> #include <string>
#include <chrono> #include <chrono>
#include <string_view> #include <string_view>

View File

@ -27,11 +27,11 @@ class Compiler {
bool unknown_global_scope; // for eval/exec() call bool unknown_global_scope; // for eval/exec() call
// for parsing token stream // for parsing token stream
int i = 0; int i = 0;
std::vector<Token> tokens; vector<Token> tokens;
const Token& prev() const{ return tokens.at(i-1); } const Token& prev() const{ return tokens[i-1]; }
const Token& curr() const{ return tokens.at(i); } const Token& curr() const{ return tokens[i]; }
const Token& next() const{ return tokens.at(i+1); } const Token& next() const{ return tokens[i+1]; }
const Token& err() const{ const Token& err() const{
if(i >= tokens.size()) return prev(); if(i >= tokens.size()) return prev();
return curr(); return curr();

View File

@ -37,10 +37,10 @@ struct SourceData {
CompileMode mode; CompileMode mode;
Str source; Str source;
pod_vector<const char*> line_starts; vector<const char*> line_starts;
bool is_precompiled; bool is_precompiled;
std::vector<Str> _precompiled_tokens; vector<Str> _precompiled_tokens;
SourceData(std::string_view source, const Str& filename, CompileMode mode); SourceData(std::string_view source, const Str& filename, CompileMode mode);
SourceData(const Str& filename, CompileMode mode); SourceData(const Str& filename, CompileMode mode);

View File

@ -352,7 +352,7 @@ struct CallExpr: Expr{
Expr_ callable; Expr_ callable;
Expr_vector args; Expr_vector args;
// **a will be interpreted as a special keyword argument: {"**": a} // **a will be interpreted as a special keyword argument: {"**": a}
std::vector<std::pair<Str, Expr_>> kwargs; vector<std::pair<Str, Expr_>> kwargs;
void emit_(CodeEmitContext* ctx) override; void emit_(CodeEmitContext* ctx) override;
}; };

View File

@ -8,8 +8,8 @@
namespace pkpy { namespace pkpy {
struct ManagedHeap{ struct ManagedHeap{
std::vector<PyObject*> _no_gc; vector<PyObject*> _no_gc;
std::vector<PyObject*> gen; vector<PyObject*> gen;
VM* vm; VM* vm;
void (*_gc_on_delete)(VM*, PyObject*) = nullptr; void (*_gc_on_delete)(VM*, PyObject*) = nullptr;
void (*_gc_marker_ex)(VM*) = nullptr; void (*_gc_marker_ex)(VM*) = nullptr;

View File

@ -30,7 +30,7 @@ constexpr const char* kTokens[] = {
}; };
using TokenValue = std::variant<std::monostate, i64, f64, Str>; using TokenValue = std::variant<std::monostate, i64, f64, Str>;
const TokenIndex kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]); const int kTokenCount = sizeof(kTokens) / sizeof(kTokens[0]);
constexpr TokenIndex TK(const char token[]) { constexpr TokenIndex TK(const char token[]) {
for(int k=0; k<kTokenCount; k++){ for(int k=0; k<kTokenCount; k++){
@ -99,7 +99,7 @@ struct Lexer {
const char* token_start; const char* token_start;
const char* curr_char; const char* curr_char;
int current_line = 1; int current_line = 1;
std::vector<Token> nexts; vector<Token> nexts;
stack_no_copy<int, small_vector_2<int, 8>> indents; stack_no_copy<int, small_vector_2<int, 8>> indents;
int brackets_level = 0; int brackets_level = 0;
@ -129,7 +129,7 @@ struct Lexer {
void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); } void SyntaxError(){ throw_err("SyntaxError", "invalid syntax"); }
void IndentationError(Str msg){ throw_err("IndentationError", msg); } void IndentationError(Str msg){ throw_err("IndentationError", msg); }
Lexer(VM* vm, std::shared_ptr<SourceData> src); Lexer(VM* vm, std::shared_ptr<SourceData> src);
std::vector<Token> run(); vector<Token> run();
}; };

View File

@ -13,17 +13,11 @@ constexpr T default_invalid_value(){
else return Discarded(); else return Discarded();
} }
template<typename T>
struct NameDictItem{
StrName first;
T second;
};
template<typename T> template<typename T>
struct NameDictImpl { struct NameDictImpl {
PK_ALWAYS_PASS_BY_POINTER(NameDictImpl) PK_ALWAYS_PASS_BY_POINTER(NameDictImpl)
using Item = NameDictItem<T>; using Item = std::pair<StrName, T>;
static constexpr uint16_t kInitialCapacity = 16; static constexpr uint16_t kInitialCapacity = 16;
static_assert(is_pod_v<T>); static_assert(is_pod_v<T>);
@ -166,19 +160,21 @@ while(!_items[i].first.empty()) { \
return val; return val;
} }
pod_vector<StrName> keys() const { array<StrName> keys() const {
pod_vector<StrName> v; array<StrName> v(_size);
int j = 0;
for(uint16_t i=0; i<_capacity; i++){ for(uint16_t i=0; i<_capacity; i++){
if(_items[i].first.empty()) continue; if(_items[i].first.empty()) continue;
v.push_back(_items[i].first); new (&v[j++]) StrName(_items[i].first);
} }
return v; return v;
} }
pod_vector<NameDictItem<T>> items() const{ array<Item> items() const{
pod_vector<NameDictItem<T>> v; array<Item> v(_size);
int j = 0;
apply([&](StrName key, T val){ apply([&](StrName key, T val){
v.push_back(NameDictItem<T>{key, val}); new(&v[j++]) Item(key, val);
}); });
return v; return v;
} }

View File

@ -22,7 +22,7 @@ struct _FrameRecord{
struct LineProfiler{ struct LineProfiler{
// filename -> records // filename -> records
std::map<std::string_view, std::vector<_LineRecord>> records; std::map<std::string_view, vector<_LineRecord>> records;
stack_no_copy<_FrameRecord> frames; stack_no_copy<_FrameRecord> frames;
std::set<FuncDecl*> functions; std::set<FuncDecl*> functions;

View File

@ -77,8 +77,8 @@ struct Str{
int index(const Str& sub, int start=0) const; int index(const Str& sub, int start=0) const;
Str replace(char old, char new_) const; Str replace(char old, char new_) const;
Str replace(const Str& old, const Str& new_, int count=-1) const; Str replace(const Str& old, const Str& new_, int count=-1) const;
pod_vector<std::string_view> split(const Str& sep) const; vector<std::string_view> split(const Str& sep) const;
pod_vector<std::string_view> split(char sep) const; vector<std::string_view> split(char sep) const;
int count(const Str& sub) const; int count(const Str& sub) const;
/*************unicode*************/ /*************unicode*************/
@ -127,15 +127,15 @@ struct StrName {
struct SStream{ struct SStream{
PK_ALWAYS_PASS_BY_POINTER(SStream) PK_ALWAYS_PASS_BY_POINTER(SStream)
// pod_vector<T> is allocated by pool128 so the buffer can be moved into Str without a copy
pod_vector<char> buffer; vector<char> buffer;
int _precision = -1; int _precision = -1;
bool empty() const { return buffer.empty(); } bool empty() const { return buffer.empty(); }
void setprecision(int precision) { _precision = precision; } void setprecision(int precision) { _precision = precision; }
SStream(){} SStream() {}
SStream(int guess_size){ buffer.reserve(guess_size); } SStream(int guess_size) { buffer.reserve(guess_size);}
Str str(); Str str();

View File

@ -35,8 +35,8 @@ struct Tuple {
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
}; };
struct List: pod_vector<PyVar>{ struct List: public vector<PyVar>{
using pod_vector<PyVar>::pod_vector; using vector<PyVar>::vector;
void _gc_mark(VM*) const; void _gc_mark(VM*) const;
Tuple to_tuple() const{ Tuple to_tuple() const{

View File

@ -5,147 +5,216 @@
namespace pkpy{ namespace pkpy{
struct explicit_copy_t {
explicit explicit_copy_t() = default;
};
template<typename T> template<typename T>
struct pod_vector{ struct array{
static constexpr int SizeT = sizeof(T);
static constexpr int N = 128 / SizeT;
static constexpr int Growth = 2;
// static_assert(128 % SizeT == 0);
static_assert(is_pod_v<T>);
static_assert(N >= 4);
int _size;
int _capacity;
T* _data; T* _data;
int _size;
using size_type = int; using size_type = int;
pod_vector(): _size(0), _capacity(N) { array(): _data(nullptr), _size(0) {}
_data = (T*)pool128_alloc(_capacity * SizeT); array(int size): _data((T*)malloc(sizeof(T) * size)), _size(size) {}
} array(array&& other) noexcept: _data(other._data), _size(other._size) {
// support initializer list
pod_vector(std::initializer_list<T> il): _size(il.size()), _capacity(std::max(N, _size)) {
_data = (T*)pool128_alloc(_capacity * SizeT);
for(int i=0; i<_size; i++) _data[i] = *(il.begin() + i);
}
pod_vector(int size): _size(size), _capacity(std::max(N, size)) {
_data = (T*)pool128_alloc(_capacity * SizeT);
}
pod_vector(const pod_vector& other): _size(other._size), _capacity(other._capacity) {
_data = (T*)pool128_alloc(_capacity * SizeT);
memcpy(_data, other._data, SizeT * _size);
}
pod_vector(pod_vector&& other) noexcept {
_size = other._size;
_capacity = other._capacity;
_data = other._data;
other._data = nullptr; other._data = nullptr;
other._size = 0;
}
array(const array& other) = delete;
array(explicit_copy_t, const array& other) {
_data = (T*)malloc(sizeof(T) * other._size);
_size = other._size;
for(int i=0; i<_size; i++) _data[i] = other._data[i];
} }
pod_vector& operator=(pod_vector&& other) noexcept { array& operator=(array&& other) noexcept{
if(_data!=nullptr) pool128_dealloc(_data); if(_data){
_size = other._size; std::destroy(begin(), end());
_capacity = other._capacity; free(_data);
}
_data = other._data; _data = other._data;
_size = other._size;
other._data = nullptr; other._data = nullptr;
other._size = 0;
return *this; return *this;
} }
// remove copy assignment array& operator=(const array& other) = delete;
pod_vector& operator=(const pod_vector& other) = delete;
template<typename __ValueT> T& operator[](int i) {
void push_back(__ValueT&& t) { PK_DEBUG_ASSERT(i>=0 && i<_size);
if (_size == _capacity) reserve(_capacity*Growth); return _data[i];
_data[_size++] = std::forward<__ValueT>(t);
} }
template<typename... Args> const T& operator[](int i) const {
void emplace_back(Args&&... args) { PK_DEBUG_ASSERT(i>=0 && i<_size);
if (_size == _capacity) reserve(_capacity*Growth); return _data[i];
new (&_data[_size++]) T(std::forward<Args>(args)...);
} }
void reserve(int cap){
if(cap <= _capacity) return;
_capacity = cap;
T* old_data = _data;
_data = (T*)pool128_alloc(_capacity * SizeT);
if(old_data != nullptr){
memcpy(_data, old_data, SizeT * _size);
pool128_dealloc(old_data);
}
}
void pop_back() { _size--; }
T popx_back() { T t = std::move(_data[_size-1]); _size--; return t; }
void extend(const pod_vector& other){
for(int i=0; i<other.size(); i++) push_back(other[i]);
}
void extend(const T* begin, const T* end){
for(auto it=begin; it!=end; it++) push_back(*it);
}
T& operator[](int index) { return _data[index]; }
const T& operator[](int index) const { return _data[index]; }
T* begin() { return _data; }
T* end() { return _data + _size; }
const T* begin() const { return _data; }
const T* end() const { return _data + _size; }
T& back() { return _data[_size - 1]; }
const T& back() const { return _data[_size - 1]; }
bool empty() const { return _size == 0; }
int size() const { return _size; } int size() const { return _size; }
T* data() { return _data; }
const T* data() const { return _data; }
void clear() { _size=0; }
template<typename __ValueT> T* begin() const{ return _data; }
void insert(int i, __ValueT&& val){ T* end() const{ return _data + _size; }
if (_size == _capacity) reserve(_capacity*Growth);
for(int j=_size; j>i; j--) _data[j] = _data[j-1];
_data[i] = std::forward<__ValueT>(val);
_size++;
}
void erase(int i){
for(int j=i; j<_size-1; j++) _data[j] = _data[j+1];
_size--;
}
void reverse(){
std::reverse(_data, _data+_size);
}
void resize(int size){
if(size > _capacity) reserve(size);
_size = size;
}
std::pair<T*, int> detach() noexcept { std::pair<T*, int> detach() noexcept {
T* p = _data; std::pair<T*, int> retval(_data, _size);
int size = _size;
_data = nullptr; _data = nullptr;
_size = 0; _size = 0;
return {p, size}; return retval;
} }
~pod_vector() { ~array() {
if(_data != nullptr) pool128_dealloc(_data); if(_data){
std::destroy(begin(), end());
free(_data);
}
} }
}; };
template <typename T, typename Container=std::vector<T>> template<typename T>
struct vector{
T* _data;
int _capacity;
int _size;
using size_type = int;
vector(): _data(nullptr), _capacity(0), _size(0) {}
vector(int size):
_data((T*)malloc(sizeof(T) * size)),
_capacity(size), _size(size) {}
vector(vector&& other) noexcept:
_data(other._data), _capacity(other._capacity), _size(other._size) {
other._data = nullptr;
other._capacity = 0;
other._size = 0;
}
vector(const vector& other) = delete;
vector(explicit_copy_t, const vector& other):
_data((T*)malloc(sizeof(T) * other._size)),
_capacity(other._size), _size(other._size) {
for(int i=0; i<_size; i++) _data[i] = other._data[i];
}
// allow move
vector& operator=(vector&& other) noexcept{
if(_data){
std::destroy(begin(), end());
free(_data);
}
new (this) vector(std::move(other));
return *this;
}
// disallow copy
vector& operator=(const vector& other) = delete;
bool empty() const { return _size == 0; }
int size() const { return _size; }
int capacity() const { return _capacity; }
T& back() { return _data[_size-1]; }
T* begin() const { return _data; }
T* end() const { return _data + _size; }
T* data() const { return _data; }
void reserve(int cap){
if(cap < 4) cap = 4; // minimum capacity
if(cap <= capacity()) return;
T* new_data = (T*)malloc(sizeof(T) * cap);
if constexpr(std::is_trivially_copyable_v<T>){
memcpy(new_data, _data, sizeof(T) * _size);
}else{
for(int i=0; i<_size; i++){
new(&new_data[i]) T(std::move(_data[i]));
_data[i].~T();
}
}
if(_data) free(_data);
_data = new_data;
_capacity = cap;
}
void resize(int size){
reserve(size);
_size = size;
}
void push_back(const T& t){
if(_size == _capacity) reserve(_capacity * 2);
new (&_data[_size++]) T(t);
}
void push_back(T&& t){
if(_size == _capacity) reserve(_capacity * 2);
new(&_data[_size++]) T(std::move(t));
}
template<typename... Args>
void emplace_back(Args&&... args){
if(_size == _capacity) reserve(_capacity * 2);
new(&_data[_size++]) T(std::forward<Args>(args)...);
}
T& operator[](int i) { return _data[i]; }
const T& operator[](int i) const { return _data[i]; }
void extend(T* begin, T* end){
int n = end - begin;
reserve(_size + n);
for(int i=0; i<n; i++) new(&_data[_size++]) T(begin[i]);
}
void insert(int index, const T& t){
if(_size == _capacity) reserve(_capacity * 2);
for(int i=_size; i>index; i--) _data[i] = std::move(_data[i-1]);
_data[index] = t;
_size++;
}
void erase(int index){
for(int i=index; i<_size-1; i++) _data[i] = std::move(_data[i+1]);
_size--;
}
void pop_back(){
PK_DEBUG_ASSERT(_size > 0);
_size--;
if constexpr(!std::is_trivially_destructible_v<T>){
_data[_size].~T();
}
}
void clear(){
std::destroy(begin(), end());
_size = 0;
}
std::pair<T*, int> detach() noexcept {
std::pair<T*, int> retval(_data, _size);
_data = nullptr;
_capacity = 0;
_size = 0;
return retval;
}
void swap(vector& other){
std::swap(_data, other._data);
std::swap(_capacity, other._capacity);
std::swap(_size, other._size);
}
~vector(){
if(_data){
std::destroy(begin(), end());
free(_data);
}
}
};
template <typename T, typename Container=vector<T>>
class stack{ class stack{
Container vec; Container vec;
public: public:
@ -167,7 +236,7 @@ public:
const Container& container() const { return vec; } const Container& container() const { return vec; }
}; };
template <typename T, typename Container=std::vector<T>> template <typename T, typename Container=vector<T>>
class stack_no_copy: public stack<T, Container>{ class stack_no_copy: public stack<T, Container>{
public: public:
stack_no_copy() = default; stack_no_copy() = default;

View File

@ -74,7 +74,7 @@ struct PyTypeInfo{
PyTypeInfo(PyObject* obj, Type base, PyObject* mod, StrName name, bool subclass_enabled, Vt vt={}): PyTypeInfo(PyObject* obj, Type base, PyObject* mod, StrName name, bool subclass_enabled, Vt vt={}):
obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {} obj(obj), base(base), mod(mod), name(name), subclass_enabled(subclass_enabled), vt(vt) {}
std::vector<StrName> annotated_fields = {}; vector<StrName> annotated_fields = {};
// unary operators // unary operators
Str (*m__repr__)(VM* vm, PyVar) = nullptr; Str (*m__repr__)(VM* vm, PyVar) = nullptr;
@ -127,8 +127,8 @@ struct PyTypeInfo{
struct ImportContext{ struct ImportContext{
PK_ALWAYS_PASS_BY_POINTER(ImportContext) PK_ALWAYS_PASS_BY_POINTER(ImportContext)
std::vector<Str> pending; vector<Str> pending;
std::vector<bool> pending_is_init; // a.k.a __init__.py vector<bool> pending_is_init; // a.k.a __init__.py
ImportContext() {} ImportContext() {}
@ -159,7 +159,7 @@ public:
ManagedHeap heap; ManagedHeap heap;
ValueStack s_data; ValueStack s_data;
CallStack callstack; CallStack callstack;
std::vector<PyTypeInfo> _all_types; vector<PyTypeInfo> _all_types;
NameDict _modules; // loaded modules NameDict _modules; // loaded modules
std::map<StrName, Str> _lazy_modules; // lazy loaded modules std::map<StrName, Str> _lazy_modules; // lazy loaded modules

View File

@ -931,7 +931,7 @@ __NEXT_STEP:
if(_1 == StopIteration) break; if(_1 == StopIteration) break;
extras.push_back(_1); extras.push_back(_1);
} }
PUSH(VAR(extras)); PUSH(VAR(std::move(extras)));
} DISPATCH() } DISPATCH()
/*****************************************/ /*****************************************/
case OP_BEGIN_CLASS:{ case OP_BEGIN_CLASS:{
@ -1056,7 +1056,9 @@ __NEXT_STEP:
Exception& _e = PK_OBJ_GET(Exception, e_obj); Exception& _e = PK_OBJ_GET(Exception, e_obj);
bool is_base_frame_to_be_popped = frame == base_frame; bool is_base_frame_to_be_popped = frame == base_frame;
__pop_frame(); __pop_frame();
if(callstack.empty()) throw _e; // propagate to the top level if(callstack.empty()){
throw std::move(_e); // propagate to the top level
}
frame = &callstack.top(); frame = &callstack.top();
PUSH(e_obj); PUSH(e_obj);
if(is_base_frame_to_be_popped){ if(is_base_frame_to_be_popped){

View File

@ -1292,7 +1292,7 @@ __EAT_DOTS_END:
} }
int count = deserializer.read_count(); int count = deserializer.read_count();
std::vector<Str>& precompiled_tokens = lexer.src->_precompiled_tokens; vector<Str>& precompiled_tokens = lexer.src->_precompiled_tokens;
for(int i=0; i<count; i++){ for(int i=0; i<count; i++){
precompiled_tokens.push_back(deserializer.read_string('\n')); precompiled_tokens.push_back(deserializer.read_string('\n'));
} }
@ -1379,7 +1379,7 @@ __EAT_DOTS_END:
PyVar e_obj = vm->call(vm->builtins->attr(type), VAR(msg)); PyVar e_obj = vm->call(vm->builtins->attr(type), VAR(msg));
Exception& e = PK_OBJ_GET(Exception, e_obj); Exception& e = PK_OBJ_GET(Exception, e_obj);
e.st_push(src, lineno, cursor, ""); e.st_push(src, lineno, cursor, "");
throw e; throw std::move(e);
} }
std::string_view TokenDeserializer::read_string(char c){ std::string_view TokenDeserializer::read_string(char c){

View File

@ -73,7 +73,7 @@ __NEXT_LINE:
if(ret.size() == 0){ if(ret.size() == 0){
vm->ValueError("empty csvfile"); vm->ValueError("empty csvfile");
} }
List header = CAST(List&, ret[0]); const List& header = CAST(List&, ret[0]);
List new_ret; List new_ret;
for(int i=1; i<ret.size(); i++){ for(int i=1; i<ret.size(); i++){
const List& row = CAST(List&, ret[i]); const List& row = CAST(List&, ret[i]);

View File

@ -66,14 +66,16 @@ namespace pkpy{
} }
Str Exception::summary() const { Str Exception::summary() const {
stack<ExceptionLine> st(stacktrace);
SStream ss; SStream ss;
if(is_re) ss << "Traceback (most recent call last):\n"; if(is_re) ss << "Traceback (most recent call last):\n";
while(!st.empty()) { // while(!st.empty()) {
ss << st.top().snapshot() << '\n'; // ss << st.top().snapshot() << '\n';
st.pop(); // st.pop();
// }
const auto& container = stacktrace.container();
for(int i=container.size()-1; i>=0; i--){
ss << container[i].snapshot() << '\n';
} }
// TODO: allow users to override the behavior
if (!msg.empty()) ss << type.sv() << ": " << msg; if (!msg.empty()) ss << type.sv() << ": " << msg;
else ss << type.sv(); else ss << type.sv();
return ss.str(); return ss.str();

View File

@ -3,7 +3,8 @@
namespace pkpy{ namespace pkpy{
int ManagedHeap::sweep(){ int ManagedHeap::sweep(){
std::vector<PyObject*> alive; vector<PyObject*> alive;
alive.reserve(gen.size() / 2);
for(PyObject* obj: gen){ for(PyObject* obj: gen){
if(obj->gc_marked){ if(obj->gc_marked){
obj->gc_marked = false; obj->gc_marked = false;

View File

@ -485,7 +485,7 @@ static bool is_unicode_Lo_char(uint32_t c) {
this->indents.push(0); this->indents.push(0);
} }
std::vector<Token> Lexer::run() { vector<Token> Lexer::run() {
PK_ASSERT(curr_char == src->source.c_str()); PK_ASSERT(curr_char == src->source.c_str());
while (lex_one_token()); while (lex_one_token());
return std::move(nexts); return std::move(nexts);

View File

@ -622,7 +622,7 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
const Str& sep = CAST(Str&, args[1]); const Str& sep = CAST(Str&, args[1]);
if(sep.empty()) vm->ValueError("empty separator"); if(sep.empty()) vm->ValueError("empty separator");
pod_vector<std::string_view> parts; vector<std::string_view> parts;
if(sep.size == 1){ if(sep.size == 1){
parts = self.split(sep[0]); parts = self.split(sep[0]);
}else{ }else{
@ -635,8 +635,7 @@ void __init_builtins(VM* _vm) {
_vm->bind(_vm->_t(VM::tp_str), "splitlines(self)", [](VM* vm, ArgsView args) { _vm->bind(_vm->_t(VM::tp_str), "splitlines(self)", [](VM* vm, ArgsView args) {
const Str& self = _CAST(Str&, args[0]); const Str& self = _CAST(Str&, args[0]);
pod_vector<std::string_view> parts; vector<std::string_view> parts = self.split('\n');
parts = self.split('\n');
List ret(parts.size()); List ret(parts.size());
for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i])); for(int i=0; i<parts.size(); i++) ret[i] = VAR(Str(parts[i]));
return VAR(std::move(ret)); return VAR(std::move(ret));
@ -797,7 +796,9 @@ void __init_builtins(VM* _vm) {
}); });
} }
bool reverse = CAST(bool, args[2]); bool reverse = CAST(bool, args[2]);
if(reverse) self.reverse(); if(reverse){
std::reverse(self.begin(), self.end());
}
return vm->None; return vm->None;
}); });
@ -892,7 +893,9 @@ void __init_builtins(VM* _vm) {
List& self = _CAST(List&, args[0]); List& self = _CAST(List&, args[0]);
if(args.size() == 1+0){ if(args.size() == 1+0){
if(self.empty()) vm->IndexError("pop from empty list"); if(self.empty()) vm->IndexError("pop from empty list");
return self.popx_back(); PyVar retval = self.back();
self.pop_back();
return retval;
} }
if(args.size() == 1+1){ if(args.size() == 1+1){
i64 index = CAST(i64, args[1]); i64 index = CAST(i64, args[1]);
@ -936,7 +939,7 @@ void __init_builtins(VM* _vm) {
int n = _CAST(int, _1); int n = _CAST(int, _1);
List result; List result;
result.reserve(self.size() * n); result.reserve(self.size() * n);
for(int i = 0; i < n; i++) result.extend(self); for(int i = 0; i < n; i++) result.extend(self.begin(), self.end());
return VAR(std::move(result)); return VAR(std::move(result));
}); });
_vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) { _vm->bind_func(VM::tp_list, "__rmul__", 2, [](VM* vm, ArgsView args) {
@ -945,7 +948,7 @@ void __init_builtins(VM* _vm) {
int n = _CAST(int, args[1]); int n = _CAST(int, args[1]);
List result; List result;
result.reserve(self.size() * n); result.reserve(self.size() * n);
for(int i = 0; i < n; i++) result.extend(self); for(int i = 0; i < n; i++) result.extend(self.begin(), self.end());
return VAR(std::move(result)); return VAR(std::move(result));
}); });
@ -964,11 +967,14 @@ void __init_builtins(VM* _vm) {
return vm->None; return vm->None;
}); });
_vm->bind_func(VM::tp_list, "copy", 1, PK_LAMBDA(VAR(_CAST(List, args[0])))); _vm->bind_func(VM::tp_list, "copy", 1, [](VM* vm, ArgsView args){
const List& self = _CAST(List&, args[0]);
return VAR(List(explicit_copy_t(), self));
});
#define BIND_RICH_CMP(name, op, _t, _T) \ #define BIND_RICH_CMP(name, op, _t, _T) \
_vm->bind__##name##__(_vm->_t, [](VM* vm, PyVar lhs, PyVar rhs){ \ _vm->bind__##name##__(_vm->_t, [](VM* vm, PyVar lhs, PyVar rhs){ \
if(!is_type(rhs, vm->_t)) return vm->NotImplemented; \ if(!is_type(rhs, vm->_t)) return vm->NotImplemented; \
auto& a = _CAST(_T&, lhs); \ auto& a = _CAST(_T&, lhs); \
auto& b = _CAST(_T&, rhs); \ auto& b = _CAST(_T&, rhs); \
for(int i=0; i<a.size() && i<b.size(); i++){ \ for(int i=0; i<a.size() && i<b.size(); i++){ \
@ -993,8 +999,8 @@ void __init_builtins(VM* _vm) {
_vm->bind__add__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) { _vm->bind__add__(VM::tp_list, [](VM* vm, PyVar _0, PyVar _1) {
const List& self = _CAST(List&, _0); const List& self = _CAST(List&, _0);
const List& other = CAST(List&, _1); const List& other = CAST(List&, _1);
List new_list(self); // copy construct List new_list(explicit_copy_t(), self);
new_list.extend(other); new_list.extend(other.begin(), other.end());
return VAR(std::move(new_list)); return VAR(std::move(new_list));
}); });
@ -1637,7 +1643,7 @@ void VM::__post_init_builtin_types(){
try{ try{
// initialize dummy func_decl for exec/eval // initialize dummy func_decl for exec/eval
CodeObject_ dynamic_co = compile("def _(): pass", "<dynamic>", EXEC_MODE); CodeObject_ dynamic_co = compile("def _(): pass", "<dynamic>", EXEC_MODE);
__dynamic_func_decl = dynamic_co->func_decls.at(0); __dynamic_func_decl = dynamic_co->func_decls[0];
// initialize builtins // initialize builtins
CodeObject_ code = compile(kPythonLibs_builtins, "<builtins>", EXEC_MODE); CodeObject_ code = compile(kPythonLibs_builtins, "<builtins>", EXEC_MODE);
this->_exec(code, this->builtins); this->_exec(code, this->builtins);

View File

@ -40,7 +40,7 @@ void LineProfiler::_step(int callstack_size, Frame* frame){
} }
} }
frames.top().prev_record = &file_records.at(line); frames.top().prev_record = &file_records[line];
} }
void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){ void LineProfiler::_step_end(int callstack_size, Frame* frame, int line){
@ -87,11 +87,11 @@ Str LineProfiler::stats(){
int end_line = decl->code->end_line; int end_line = decl->code->end_line;
if(start_line == -1 || end_line == -1) continue; if(start_line == -1 || end_line == -1) continue;
std::string_view filename = decl->code->src->filename.sv(); std::string_view filename = decl->code->src->filename.sv();
std::vector<_LineRecord>& file_records = records[filename]; vector<_LineRecord>& file_records = records[filename];
if(file_records.empty()) continue; if(file_records.empty()) continue;
clock_t total_time = 0; clock_t total_time = 0;
for(int line = start_line; line <= end_line; line++){ for(int line = start_line; line <= end_line; line++){
total_time += file_records.at(line).time; total_time += file_records[line].time;
} }
ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n"; ss << "Total time: " << (f64)total_time / CLOCKS_PER_SEC << "s\n";
ss << "File: " << filename << "\n"; ss << "File: " << filename << "\n";
@ -99,7 +99,7 @@ Str LineProfiler::stats(){
ss << "Line # Hits Time Per Hit % Time Line Contents\n"; ss << "Line # Hits Time Per Hit % Time Line Contents\n";
ss << "==============================================================\n"; ss << "==============================================================\n";
for(int line = start_line; line <= end_line; line++){ for(int line = start_line; line <= end_line; line++){
const _LineRecord& record = file_records.at(line); const _LineRecord& record = file_records[line];
if(!record.is_valid()) continue; if(!record.is_valid()) continue;
ss << left_pad(std::to_string(line), 6); ss << left_pad(std::to_string(line), 6);
if(record.hits == 0){ if(record.hits == 0){

View File

@ -190,7 +190,7 @@ struct Random{
PyVar* data = view.begin(); PyVar* data = view.begin();
int size = view.size(); int size = view.size();
if(size == 0) vm->IndexError("cannot choose from an empty sequence"); if(size == 0) vm->IndexError("cannot choose from an empty sequence");
pod_vector<f64> cum_weights(size); array<f64> cum_weights(size);
if(args[2] == vm->None){ if(args[2] == vm->None){
for(int i = 0; i < size; i++) cum_weights[i] = i + 1; for(int i = 0; i < size; i++) cum_weights[i] = i + 1;
}else{ }else{

View File

@ -333,8 +333,8 @@ int utf8len(unsigned char c, bool suppress){
return _byte_index_to_unicode(size); return _byte_index_to_unicode(size);
} }
pod_vector<std::string_view> Str::split(const Str& sep) const{ vector<std::string_view> Str::split(const Str& sep) const{
pod_vector<std::string_view> result; vector<std::string_view> result;
std::string_view tmp; std::string_view tmp;
int start = 0; int start = 0;
while(true){ while(true){
@ -349,8 +349,8 @@ int utf8len(unsigned char c, bool suppress){
return result; return result;
} }
pod_vector<std::string_view> Str::split(char sep) const{ vector<std::string_view> Str::split(char sep) const{
pod_vector<std::string_view> result; vector<std::string_view> result;
int i = 0; int i = 0;
for(int j = 0; j < size; j++){ for(int j = 0; j < size; j++){
if(data[j] == sep){ if(data[j] == sep){
@ -404,29 +404,35 @@ int utf8len(unsigned char c, bool suppress){
} }
Str SStream::str(){ Str SStream::str(){
#if 0
// after this call, the buffer is no longer valid // after this call, the buffer is no longer valid
buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0' buffer.reserve(buffer.size() + 1); // allocate one more byte for '\0'
buffer[buffer.size()] = '\0'; // set '\0' buffer[buffer.size()] = '\0'; // set '\0'
return Str(buffer.detach()); return Str(buffer.detach());
#else
#warning "SStream::str() needs to be optimized"
buffer.push_back('\0');
return Str(buffer.data(), buffer.size()-1);
#endif
} }
SStream& SStream::operator<<(const Str& s){ SStream& SStream::operator<<(const Str& s){
buffer.extend(s.begin(), s.end()); for(char c: s) buffer.push_back(c);
return *this; return *this;
} }
SStream& SStream::operator<<(const char* s){ SStream& SStream::operator<<(const char* s){
buffer.extend(s, s + strlen(s)); while(*s) buffer.push_back(*s++);
return *this; return *this;
} }
SStream& SStream::operator<<(const std::string& s){ SStream& SStream::operator<<(const std::string& s){
buffer.extend(s.data(), s.data() + s.size()); for(char c: s) buffer.push_back(c);
return *this; return *this;
} }
SStream& SStream::operator<<(std::string_view s){ SStream& SStream::operator<<(std::string_view s){
buffer.extend(s.data(), s.data() + s.size()); for(char c: s) buffer.push_back(c);
return *this; return *this;
} }
@ -459,7 +465,7 @@ int utf8len(unsigned char c, bool suppress){
buffer.push_back('-'); buffer.push_back('-');
val = -val; val = -val;
} }
char* begin = buffer.end(); auto begin = buffer.end();
while(val){ while(val){
buffer.push_back('0' + val % 10); buffer.push_back('0' + val % 10);
val /= 10; val /= 10;

View File

@ -330,7 +330,7 @@ namespace pkpy{
PyVar VM::py_import(Str path, bool throw_err){ PyVar VM::py_import(Str path, bool throw_err){
if(path.empty()) vm->ValueError("empty module name"); if(path.empty()) vm->ValueError("empty module name");
static auto f_join = [](const pod_vector<std::string_view>& cpnts){ static auto f_join = [](const vector<std::string_view>& cpnts){
SStream ss; SStream ss;
for(int i=0; i<cpnts.size(); i++){ for(int i=0; i<cpnts.size(); i++){
if(i != 0) ss << "."; if(i != 0) ss << ".";
@ -346,7 +346,7 @@ namespace pkpy{
Str curr_path = __import_context.pending.back(); Str curr_path = __import_context.pending.back();
bool curr_is_init = __import_context.pending_is_init.back(); bool curr_is_init = __import_context.pending_is_init.back();
// convert relative path to absolute path // convert relative path to absolute path
pod_vector<std::string_view> cpnts = curr_path.split('.'); vector<std::string_view> cpnts = curr_path.split('.');
int prefix = 0; // how many dots in the prefix int prefix = 0; // how many dots in the prefix
for(int i=0; i<path.length(); i++){ for(int i=0; i<path.length(); i++){
if(path[i] == '.') prefix++; if(path[i] == '.') prefix++;
@ -366,7 +366,7 @@ namespace pkpy{
PyVar ext_mod = _modules.try_get(name); PyVar ext_mod = _modules.try_get(name);
if(ext_mod != nullptr) return ext_mod; if(ext_mod != nullptr) return ext_mod;
pod_vector<std::string_view> path_cpnts = path.split('.'); vector<std::string_view> path_cpnts = path.split('.');
// check circular import // check circular import
if(__import_context.pending.size() > 128){ if(__import_context.pending.size() > 128){
ImportError("maximum recursion depth exceeded while importing"); ImportError("maximum recursion depth exceeded while importing");
@ -769,7 +769,7 @@ Str VM::disassemble(CodeObject_ co){
return s + std::string(n - s.length(), ' '); return s + std::string(n - s.length(), ' ');
}; };
std::vector<int> jumpTargets; vector<int> jumpTargets;
for(int i=0; i<co->codes.size(); i++){ for(int i=0; i<co->codes.size(); i++){
Bytecode byte = co->codes[i]; Bytecode byte = co->codes[i];
if(byte.is_forward_jump()){ if(byte.is_forward_jump()){
@ -1442,7 +1442,7 @@ void VM::_error(PyVar e_obj){
Exception& e = PK_OBJ_GET(Exception, e_obj); Exception& e = PK_OBJ_GET(Exception, e_obj);
if(callstack.empty()){ if(callstack.empty()){
e.is_re = false; e.is_re = false;
throw e; throw std::move(e);
} }
PUSH(e_obj); PUSH(e_obj);
__raise_exc(); __raise_exc();
@ -1665,7 +1665,7 @@ void VM::__breakpoint(){
bool show_headers = true; bool show_headers = true;
while(true){ while(true){
std::vector<LinkedFrame*> frames; vector<LinkedFrame*> frames;
LinkedFrame* lf = callstack._tail; LinkedFrame* lf = callstack._tail;
while(lf != nullptr){ while(lf != nullptr){
frames.push_back(lf); frames.push_back(lf);