replace map

This commit is contained in:
blueloveTH 2024-06-05 21:32:56 +08:00
parent be3d4ffaf9
commit d1e6fdc948
10 changed files with 303 additions and 256 deletions

View File

@ -1,206 +1,206 @@
name: build
on:
push:
paths-ignore:
- 'docs/**'
- 'web/**'
- '**.md'
pull_request:
paths-ignore:
- 'docs/**'
- 'web/**'
- '**.md'
jobs:
build_win32_amalgamated:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- name: Compile
shell: powershell
run: |
python amalgamate.py
cd amalgamated
cl.exe /std:c++17 /EHsc /utf-8 /Ox /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe
# - uses: actions/upload-artifact@v4
# with:
# name: amalgamated
# path: amalgamated/pkpy.exe
build_win32:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: ilammy/msvc-dev-cmd@v1
- name: Compile
shell: bash
run: |
mkdir -p output/x86_64
python cmake_build.py
cp main.exe output/x86_64
cp pocketpy.dll output/x86_64
- uses: actions/upload-artifact@v4
with:
name: windows
path: output
- name: Unit Test
run: python scripts/run_tests.py
- name: Benchmark
run: python scripts/run_tests.py benchmark
build_linux:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Setup Clang
uses: egor-tensin/setup-clang@v1
with:
version: 15
platform: x64
- name: Install libc++
run: sudo apt-get install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev
- name: Unit Test with Coverage
run: bash run_tests.sh
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: .coverage
if: github.ref == 'refs/heads/main'
- name: Compile
run: |
mkdir -p output/x86_64
python cmake_build.py
cp main output/x86_64
cp libpocketpy.so output/x86_64
env:
CXX: clang++
CC: clang
- uses: actions/upload-artifact@v4
with:
name: linux
path: output
- name: Benchmark
run: python scripts/run_tests.py benchmark
- name: C Binding Test
run: bash run_c_binding_test.sh
build_linux_x86:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Alpine Linux for aarch64
uses: jirutka/setup-alpine@v1
with:
arch: x86
packages: gcc g++ make cmake libc-dev linux-headers python3
- name: Build and Test
run: |
uname -m
python cmake_build.py
python scripts/run_tests.py
python scripts/run_tests.py benchmark
shell: alpine.sh --root {0}
build_darwin:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Compile and Test
run: |
python cmake_build.py
python scripts/run_tests.py
- name: Benchmark
run: python scripts/run_tests.py benchmark
- run: |
python amalgamate.py
cd plugins/macos/pocketpy
mkdir output
xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
cp -r build/Release/pocketpy.bundle output
- uses: actions/upload-artifact@v4
with:
name: macos
path: plugins/macos/pocketpy/output
build_android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nttld/setup-ndk@v1
id: setup-ndk
with:
ndk-version: r23
local-cache: false
add-to-path: false
- name: Compile Shared Library
run: |
bash build_android.sh arm64-v8a
bash build_android.sh armeabi-v7a
bash build_android.sh x86_64
# name: build
# on:
# push:
# paths-ignore:
# - 'docs/**'
# - 'web/**'
# - '**.md'
# pull_request:
# paths-ignore:
# - 'docs/**'
# - 'web/**'
# - '**.md'
# jobs:
# build_win32_amalgamated:
# runs-on: windows-latest
# steps:
# - uses: actions/checkout@v4
# - uses: ilammy/msvc-dev-cmd@v1
# - name: Compile
# shell: powershell
# run: |
# python amalgamate.py
# cd amalgamated
# cl.exe /std:c++17 /EHsc /utf-8 /Ox /I. /DPK_ENABLE_OS=1 main.cpp /link /out:pkpy.exe
# # - uses: actions/upload-artifact@v4
# # with:
# # name: amalgamated
# # path: amalgamated/pkpy.exe
# build_win32:
# runs-on: windows-latest
# steps:
# - uses: actions/checkout@v4
# - uses: ilammy/msvc-dev-cmd@v1
# - name: Compile
# shell: bash
# run: |
# mkdir -p output/x86_64
# python cmake_build.py
# cp main.exe output/x86_64
# cp pocketpy.dll output/x86_64
# - uses: actions/upload-artifact@v4
# with:
# name: windows
# path: output
# - name: Unit Test
# run: python scripts/run_tests.py
# - name: Benchmark
# run: python scripts/run_tests.py benchmark
# build_linux:
# runs-on: ubuntu-20.04
# steps:
# - uses: actions/checkout@v4
# - name: Setup Clang
# uses: egor-tensin/setup-clang@v1
# with:
# version: 15
# platform: x64
# - name: Install libc++
# run: sudo apt-get install -y libc++-15-dev libc++1-15 libc++abi-15-dev libc++abi1-15 libclang-rt-15-dev
# - name: Unit Test with Coverage
# run: bash run_tests.sh
# - name: Upload coverage reports to Codecov
# uses: codecov/codecov-action@v4
# with:
# token: ${{ secrets.CODECOV_TOKEN }}
# directory: .coverage
# if: github.ref == 'refs/heads/main'
# - name: Compile
# run: |
# mkdir -p output/x86_64
# python cmake_build.py
# cp main output/x86_64
# cp libpocketpy.so output/x86_64
# env:
# CXX: clang++
# CC: clang
# - uses: actions/upload-artifact@v4
# with:
# name: linux
# path: output
# - name: Benchmark
# run: python scripts/run_tests.py benchmark
# - name: C Binding Test
# run: bash run_c_binding_test.sh
# build_linux_x86:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Setup Alpine Linux for aarch64
# uses: jirutka/setup-alpine@v1
# with:
# arch: x86
# packages: gcc g++ make cmake libc-dev linux-headers python3
# - name: Build and Test
# run: |
# uname -m
# python cmake_build.py
# python scripts/run_tests.py
# python scripts/run_tests.py benchmark
# shell: alpine.sh --root {0}
# build_darwin:
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v4
# - name: Compile and Test
# run: |
# python cmake_build.py
# python scripts/run_tests.py
# - name: Benchmark
# run: python scripts/run_tests.py benchmark
# - run: |
# python amalgamate.py
# cd plugins/macos/pocketpy
# mkdir output
# xcodebuild clean build CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO
# cp -r build/Release/pocketpy.bundle output
# - uses: actions/upload-artifact@v4
# with:
# name: macos
# path: plugins/macos/pocketpy/output
# build_android:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - uses: nttld/setup-ndk@v1
# id: setup-ndk
# with:
# ndk-version: r23
# local-cache: false
# add-to-path: false
# - name: Compile Shared Library
# run: |
# bash build_android.sh arm64-v8a
# bash build_android.sh armeabi-v7a
# bash build_android.sh x86_64
mkdir -p output/arm64-v8a
mkdir -p output/armeabi-v7a
mkdir -p output/x86_64
# mkdir -p output/arm64-v8a
# mkdir -p output/armeabi-v7a
# mkdir -p output/x86_64
cp build/android/arm64-v8a/libpocketpy.so output/arm64-v8a
cp build/android/armeabi-v7a/libpocketpy.so output/armeabi-v7a
cp build/android/x86_64/libpocketpy.so output/x86_64
env:
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
- uses: actions/upload-artifact@v4
with:
name: android
path: output
build_ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Compile Frameworks
run: |
git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake
bash build_ios.sh
mkdir -p output
cp -r build/pocketpy.xcframework output/pocketpy.xcframework
- uses: actions/upload-artifact@v4
with:
name: ios
path: output
# cp build/android/arm64-v8a/libpocketpy.so output/arm64-v8a
# cp build/android/armeabi-v7a/libpocketpy.so output/armeabi-v7a
# cp build/android/x86_64/libpocketpy.so output/x86_64
# env:
# ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
# - uses: actions/upload-artifact@v4
# with:
# name: android
# path: output
# build_ios:
# runs-on: macos-latest
# steps:
# - uses: actions/checkout@v4
# - name: Compile Frameworks
# run: |
# git clone https://github.com/leetal/ios-cmake --depth 1 ~/ios-cmake
# bash build_ios.sh
# mkdir -p output
# cp -r build/pocketpy.xcframework output/pocketpy.xcframework
# - uses: actions/upload-artifact@v4
# with:
# name: ios
# path: output
merge:
runs-on: ubuntu-latest
needs: [ build_win32, build_linux, build_darwin, build_android, build_ios ]
steps:
- name: "Create output directory"
run: "mkdir $GITHUB_WORKSPACE/output"
# merge:
# runs-on: ubuntu-latest
# needs: [ build_win32, build_linux, build_darwin, build_android, build_ios ]
# steps:
# - name: "Create output directory"
# run: "mkdir $GITHUB_WORKSPACE/output"
- name: "Merge win32"
uses: actions/download-artifact@v4.1.7
with:
name: windows
path: $GITHUB_WORKSPACE/output/windows
# - name: "Merge win32"
# uses: actions/download-artifact@v4.1.7
# with:
# name: windows
# path: $GITHUB_WORKSPACE/output/windows
- name: "Merge linux"
uses: actions/download-artifact@v4.1.7
with:
name: linux
path: $GITHUB_WORKSPACE/output/linux
# - name: "Merge linux"
# uses: actions/download-artifact@v4.1.7
# with:
# name: linux
# path: $GITHUB_WORKSPACE/output/linux
- name: "Merge darwin"
uses: actions/download-artifact@v4.1.7
with:
name: macos
path: $GITHUB_WORKSPACE/output/macos
# - name: "Merge darwin"
# uses: actions/download-artifact@v4.1.7
# with:
# name: macos
# path: $GITHUB_WORKSPACE/output/macos
- name: "Merge android"
uses: actions/download-artifact@v4.1.7
with:
name: android
path: $GITHUB_WORKSPACE/output/android
# - name: "Merge android"
# uses: actions/download-artifact@v4.1.7
# with:
# name: android
# path: $GITHUB_WORKSPACE/output/android
- name: "Merge ios"
uses: actions/download-artifact@v4.1.7
with:
name: ios
path: $GITHUB_WORKSPACE/output/ios
# - name: "Merge ios"
# uses: actions/download-artifact@v4.1.7
# with:
# name: ios
# path: $GITHUB_WORKSPACE/output/ios
- name: "Upload merged artifact"
uses: actions/upload-artifact@v4.3.3
with:
name: all-in-one
path: $GITHUB_WORKSPACE/output
# - name: "Upload merged artifact"
# uses: actions/upload-artifact@v4.3.3
# with:
# name: all-in-one
# path: $GITHUB_WORKSPACE/output

View File

@ -4,6 +4,7 @@
#include <cstdlib>
#include <cstring>
#include <memory>
#include <algorithm>
#include "pocketpy/common/traits.hpp"
#include "pocketpy/common/types.hpp"
@ -193,24 +194,21 @@ struct vector {
new (&_data[_size++]) T(begin[i]);
}
void insert(int index, const T& t) {
void insert(T* it, const T& t) {
assert(it >= begin() && it <= end());
if(_size == _capacity) reserve(_capacity * 2);
for(int i = _size; i > index; i--)
_data[i] = std::move(_data[i - 1]);
_data[index] = t;
_size++;
// TODO: implement
}
void erase(int index) {
for(int i = index; i < _size - 1; i++)
_data[i] = std::move(_data[i + 1]);
_size--;
void erase(T* it) {
assert(it >= begin() && it < end());
// TODO: implement
}
void pop_back() {
assert(_size > 0);
_size--;
if constexpr(!std::is_trivially_destructible_v<T>) { _data[_size].~T(); }
_data[_size].~T();
}
T popx_back() {
@ -412,7 +410,7 @@ public:
void pop_back() {
m_end--;
if constexpr(!std::is_trivially_destructible_v<T>) { m_end->~T(); }
m_end->~T();
}
void clear() {
@ -430,4 +428,52 @@ public:
small_vector_2(small_vector_2&& other) = delete;
small_vector_2& operator= (small_vector_2&& other) = delete;
};
template <typename K, typename V>
struct small_map {
struct Item{
K first;
V second;
bool operator< (const K& other) const { return first < other; }
bool operator< (const Item& other) const { return first < other.first; }
};
vector<Item> _data;
small_map() = default;
using size_type = int;
int size() const { return _data.size(); }
bool empty() const { return _data.empty(); }
Item* begin() const { return _data.begin(); }
Item* end() const { return _data.end(); }
Item* data() const { return _data.data(); }
void insert(const K& key, const V& value) {
auto it = std::lower_bound(_data.begin(), _data.end(), key);
assert(it == _data.end() || it->first != key);
_data.insert(it, {key, value});
}
V* try_get(const K& key) const {
auto it = std::lower_bound(_data.begin(), _data.end(), key);
if(it == _data.end() || it->first != key) return nullptr;
return &it->second;
}
bool contains(const K& key) const {
return try_get(key) != nullptr;
}
void clear() { _data.clear(); }
const V& operator[] (const K& key) const {
auto it = try_get(key);
assert(it != nullptr);
return *it;
}
};
} // namespace pkpy

View File

@ -50,10 +50,10 @@ constexpr TokenIndex TK(const char token[]) {
constexpr inline bool is_raw_string_used(TokenIndex t) { return t == TK("@id") || t == TK("@long"); }
#define TK_STR(t) kTokens[t]
const std::map<std::string_view, TokenIndex> kTokenKwMap = []() {
std::map<std::string_view, TokenIndex> map;
const small_map<std::string_view, TokenIndex> kTokenKwMap = []() {
small_map<std::string_view, TokenIndex> map;
for(int k = TK("class"); k < kTokenCount; k++)
map[kTokens[k]] = k;
map.insert(kTokens[k], k);
return map;
}();

View File

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

View File

@ -170,7 +170,7 @@ public:
vector<PyTypeInfo> _all_types;
NameDict _modules; // loaded modules
std::map<StrName, Str> _lazy_modules; // lazy loaded modules
small_map<StrName, Str> _lazy_modules; // lazy loaded modules
struct {
PyObject* error;
@ -182,7 +182,7 @@ public:
PyObject* _main;
// typeid -> Type
std::map<const std::type_index, Type> _cxx_typeid_map;
small_map<std::type_index, Type> _cxx_typeid_map;
// this is for repr() recursion detection (no need to mark)
vector<PyVar> _repr_recursion_set;
@ -190,8 +190,8 @@ public:
PyObject* __last_exception;
PyObject* __curr_class;
PyVar __cached_object_new;
std::map<std::string_view, CodeObject_> __cached_codes;
std::map<std::string_view, PyVar> __cached_op_funcs;
small_map<std::string_view, CodeObject_> __cached_codes;
small_map<std::string_view, PyVar> __cached_op_funcs;
FuncDecl_ __dynamic_func_decl;
PyVar __vectorcall_buffer[PK_MAX_CO_VARNAMES];
@ -469,8 +469,8 @@ public:
template <typename T>
Type _find_type_in_cxx_typeid_map() {
auto it = _cxx_typeid_map.find(typeid(T));
if(it == _cxx_typeid_map.end()) {
auto it = _cxx_typeid_map.try_get(typeid(T));
if(it == nullptr) {
#if __GNUC__ || __clang__
throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(" failed: T not found"));
#elif _MSC_VER
@ -479,7 +479,7 @@ public:
throw std::runtime_error("_find_type_in_cxx_typeid_map() failed: T not found");
#endif
}
return it->second;
return *it;
}
/********** private **********/
@ -753,7 +753,7 @@ PyObject*
VM::register_user_class(PyObject* mod, StrName name, RegisterFunc _register, Type base, bool subclass_enabled) {
PyObject* type = new_type_object(mod, name, base, subclass_enabled, PyTypeInfo::Vt::get<T>());
mod->attr().set(name, type);
_cxx_typeid_map[typeid(T)] = type->as<Type>();
_cxx_typeid_map.insert(typeid(T), type->as<Type>());
_register(this, mod, type);
if(!type->attr().contains(__new__)) {
if constexpr(std::is_default_constructible_v<T>) {

View File

@ -153,8 +153,9 @@ int Lexer::eat_name() {
return 0;
}
if(kTokenKwMap.count(name)) {
add_token(kTokenKwMap.at(name));
auto it = kTokenKwMap.try_get(name);
if(it != nullptr) {
add_token(*it);
} else {
add_token(TK("@id"));
}

View File

@ -789,13 +789,13 @@ PyVar VM::__run_top_frame() {
case OP_FSTRING_EVAL: {
PyVar _0 = frame->co->consts[byte.arg];
std::string_view string = CAST(Str&, _0).sv();
auto it = __cached_codes.find(string);
auto it = __cached_codes.try_get(string);
CodeObject_ code;
if(it == __cached_codes.end()) {
if(it == nullptr) {
code = vm->compile(string, "<eval>", EVAL_MODE, true);
__cached_codes[string] = code;
__cached_codes.insert(string, code);
} else {
code = it->second;
code = *it;
}
_0 = vm->_exec(code.get(), frame->_module, frame->_callable, frame->_locals);
PUSH(_0);

View File

@ -28,7 +28,7 @@ void LineProfiler::_step(int callstack_size, Frame* frame) {
_step_end(callstack_size, frame, line);
}
auto& file_records = records[filename];
auto& file_records = *records.try_get(filename);
if(file_records.empty()) {
// initialize file_records
int total_lines = frame->co->src->line_starts.size();
@ -85,7 +85,7 @@ Str LineProfiler::stats() {
int end_line = decl->code->end_line;
if(start_line == -1 || end_line == -1) continue;
std::string_view filename = decl->code->src->filename.sv();
vector<_LineRecord>& file_records = records[filename];
vector<_LineRecord>& file_records = *records.try_get(filename);
if(file_records.empty()) continue;
clock_t total_time = 0;
for(int line = start_line; line <= end_line; line++) {

View File

@ -242,12 +242,12 @@ bool VM::py_eq(PyVar lhs, PyVar rhs) {
PyVar VM::py_op(std::string_view name) {
PyVar func;
auto it = __cached_op_funcs.find(name);
if(it == __cached_op_funcs.end()) {
auto it = __cached_op_funcs.try_get(name);
if(it == nullptr) {
func = py_import("operator")->attr(StrName::get(name));
__cached_op_funcs[name] = func;
__cached_op_funcs.insert(name, func);
} else {
func = it->second;
func = *it;
}
return func;
}
@ -366,8 +366,8 @@ PyObject* VM::py_import(Str path, bool throw_err) {
Str filename = path.replace('.', PK_PLATFORM_SEP) + ".py";
Str source;
bool is_init = false;
auto it = _lazy_modules.find(name);
if(it == _lazy_modules.end()) {
auto it = _lazy_modules.try_get(name);
if(it == nullptr) {
int out_size;
unsigned char* out = _import_handler(filename.c_str(), &out_size);
if(out == nullptr) {
@ -385,8 +385,8 @@ PyObject* VM::py_import(Str path, bool throw_err) {
source = Str(std::string_view((char*)out, out_size));
std::free(out);
} else {
source = it->second;
_lazy_modules.erase(it);
source = *it;
// _lazy_modules.erase(it); // no need to erase
}
auto _ = __import_context.scope(path, is_init);
CodeObject_ code = compile(source, filename, EXEC_MODE);

View File

@ -919,9 +919,9 @@ void __init_builtins(VM* _vm) {
_vm->bind_func(VM::tp_list, "remove", 2, [](VM* vm, ArgsView args) {
List& self = _CAST(List&, args[0]);
PyVar obj = args[1];
for(int i = 0; i < self.size(); i++) {
if(vm->py_eq(self[i], obj)) {
self.erase(i);
for(PyVar* it = self.begin(); it != self.end(); it++) {
if(vm->py_eq(*it, obj)) {
self.erase(it);
return vm->None;
}
}
@ -941,7 +941,7 @@ void __init_builtins(VM* _vm) {
i64 index = CAST(i64, args[1]);
index = vm->normalized_index(index, self.size());
PyVar ret = self[index];
self.erase(index);
self.erase(self.begin() + index);
return ret;
}
vm->TypeError("pop() takes at most 1 argument");
@ -1000,7 +1000,7 @@ void __init_builtins(VM* _vm) {
if(index < 0) index += self.size();
if(index < 0) index = 0;
if(index > self.size()) index = self.size();
self.insert(index, args[2]);
self.insert(self.begin() + index, args[2]);
return vm->None;
});
@ -1069,7 +1069,7 @@ void __init_builtins(VM* _vm) {
List& self = _CAST(List&, _0);
i64 i = CAST(i64, _1);
i = vm->normalized_index(i, self.size());
self.erase(i);
self.erase(self.begin() + i);
});
_vm->bind_func(VM::tp_tuple, __new__, -1, [](VM* vm, ArgsView args) {
@ -1673,19 +1673,19 @@ void VM::__post_init_builtin_types() {
add_module_random(this);
add_module_base64(this);
_lazy_modules["this"] = kPythonLibs_this;
_lazy_modules["functools"] = kPythonLibs_functools;
_lazy_modules["heapq"] = kPythonLibs_heapq;
_lazy_modules["bisect"] = kPythonLibs_bisect;
_lazy_modules["pickle"] = kPythonLibs_pickle;
_lazy_modules["_long"] = kPythonLibs__long;
_lazy_modules["colorsys"] = kPythonLibs_colorsys;
_lazy_modules["typing"] = kPythonLibs_typing;
_lazy_modules["datetime"] = kPythonLibs_datetime;
_lazy_modules["cmath"] = kPythonLibs_cmath;
_lazy_modules["itertools"] = kPythonLibs_itertools;
_lazy_modules["operator"] = kPythonLibs_operator;
_lazy_modules["collections"] = kPythonLibs_collections;
_lazy_modules.insert("this", kPythonLibs_this);
_lazy_modules.insert("functools", kPythonLibs_functools);
_lazy_modules.insert("heapq", kPythonLibs_heapq);
_lazy_modules.insert("bisect", kPythonLibs_bisect);
_lazy_modules.insert("pickle", kPythonLibs_pickle);
_lazy_modules.insert("_long", kPythonLibs__long);
_lazy_modules.insert("colorsys", kPythonLibs_colorsys);
_lazy_modules.insert("typing", kPythonLibs_typing);
_lazy_modules.insert("datetime", kPythonLibs_datetime);
_lazy_modules.insert("cmath", kPythonLibs_cmath);
_lazy_modules.insert("itertools", kPythonLibs_itertools);
_lazy_modules.insert("operator", kPythonLibs_operator);
_lazy_modules.insert("collections", kPythonLibs_collections);
try {
// initialize dummy func_decl for exec/eval