pax_global_header00006660000000000000000000000064146711750540014524gustar00rootroot0000000000000052 comment=3231280f4406641a642983a80885c0a31001d4bc tbox-1.7.6/000077500000000000000000000000001467117505400125135ustar00rootroot00000000000000tbox-1.7.6/.github/000077500000000000000000000000001467117505400140535ustar00rootroot00000000000000tbox-1.7.6/.github/workflows/000077500000000000000000000000001467117505400161105ustar00rootroot00000000000000tbox-1.7.6/.github/workflows/android.yml000066400000000000000000000011171467117505400202530ustar00rootroot00000000000000name: Android on: pull_request: push: jobs: build: strategy: matrix: os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Prepare run: | wget -q https://dl.google.com/android/repository/android-ndk-r21-linux-x86_64.zip unzip -q -o ./android-ndk-r21-linux-x86_64.zip - name: Tests run: | xmake f -p android --ndk=`pwd`/android-ndk-r21 xmake tbox-1.7.6/.github/workflows/cross_musl.yml000066400000000000000000000013041467117505400210220ustar00rootroot00000000000000name: Cross (Musl) on: pull_request: push: jobs: build: strategy: matrix: os: [ubuntu-latest] cross: [arm-linux-musleabi, aarch64-linux-musl] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Installation run: | wget https://github.com/xmake-mirror/musl.cc/releases/download/20210202/${{ matrix.cross }}-cross.linux.tgz tar -xvf ${{ matrix.cross }}-cross.linux.tgz - name: Tests run: | xmake f -p cross --toolchain=muslcc --sdk=`pwd`/${{ matrix.cross }}-cross xmake tbox-1.7.6/.github/workflows/fedora.yml000066400000000000000000000015551467117505400201010ustar00rootroot00000000000000name: Fedora on: pull_request: push: release: types: [published] jobs: build: container: fedora:latest runs-on: ubuntu-latest steps: - name: Prepare build tools run: | uname -a dnf -y install @development-tools @rpm-development-tools dnf -y install copr-cli make gcc-c++ dnf -y install perl dnf -y upgrade git - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Tests env: XMAKE_ROOT: y run: | xmake xmake run demo xmake f -m debug xmake -r xmake run demo xmake f --micro=y xmake -r xmake run demo xmake f --small=y -m debug xmake -r xmake run demo tbox-1.7.6/.github/workflows/iphoneos.yml000066400000000000000000000005701467117505400204610ustar00rootroot00000000000000name: iPhoneOS on: pull_request: push: jobs: build: strategy: matrix: os: [macOS-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Tests run: | xmake f -p iphoneos xmake tbox-1.7.6/.github/workflows/issue-translator.yml000066400000000000000000000005451467117505400221560ustar00rootroot00000000000000name: 'issue-translator' on: issue_comment: types: [created] issues: types: [opened] jobs: build: runs-on: ubuntu-latest steps: - uses: usthe/issues-translate-action@v2.7 with: IS_MODIFY_TITLE: false CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. tbox-1.7.6/.github/workflows/linux.yml000066400000000000000000000011211467117505400177650ustar00rootroot00000000000000name: Linux on: pull_request: push: jobs: build: strategy: matrix: os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Tests run: | xmake xmake run demo xmake f -m debug xmake -r xmake run demo xmake f --micro=y xmake -r xmake run demo xmake f --small=y -m debug xmake -r xmake run demo tbox-1.7.6/.github/workflows/macos.yml000066400000000000000000000011201467117505400177270ustar00rootroot00000000000000name: macOS on: pull_request: push: jobs: build: strategy: matrix: os: [macOS-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Tests run: | xmake xmake run demo xmake f -m debug xmake -r xmake run demo xmake f --micro=y xmake -r xmake run demo xmake f --small=y -m debug xmake -r xmake run demo tbox-1.7.6/.github/workflows/mingw_macos.yml000066400000000000000000000007021467117505400211350ustar00rootroot00000000000000name: MingW (MacOS) on: pull_request: push: jobs: build: strategy: matrix: os: [macOS-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Prepare run: | brew install mingw-w64 - name: Tests run: | xmake f -p mingw xmake tbox-1.7.6/.github/workflows/mingw_msys2.yml000066400000000000000000000022021467117505400211050ustar00rootroot00000000000000name: MingW (Msys2) on: push: pull_request: jobs: build: runs-on: windows-latest strategy: fail-fast: false matrix: include: [ { msystem: MINGW64, arch: x86_64, prefix: /mingw64 }, { msystem: MINGW32, arch: i686, prefix: /mingw32 } ] steps: - uses: actions/checkout@v1 - uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.msystem }} install: git base-devel unzip mingw-w64-${{ matrix.arch }}-toolchain update: true - name: Prepare shell: msys2 {0} run: | git clone https://github.com/xmake-io/xmake.git --recurse-submodules -b dev xmakesrc cd xmakesrc ./configure make build make install PREFIX=${{ matrix.prefix }} xmake --version cd .. git reset --hard HEAD git clean -fdx - name: Tests shell: msys2 {0} run: | if [ "${{ matrix.arch }}" == "x86_64" ]; then xmake f -p mingw -a x86_64 else xmake f -p mingw -a i386 fi xmake tbox-1.7.6/.github/workflows/wasm.yml000066400000000000000000000006001467117505400175760ustar00rootroot00000000000000name: Wasm on: pull_request: push: jobs: build: strategy: matrix: os: [ubuntu-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Tests run: | xmake f -p wasm --demo=n --yes xmake tbox-1.7.6/.github/workflows/windows.yml000066400000000000000000000013071467117505400203260ustar00rootroot00000000000000name: Windows on: pull_request: push: jobs: build: strategy: matrix: os: [windows-latest] arch: [x64, x86] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v1 - uses: xmake-io/github-action-setup-xmake@v1 with: xmake-version: branch@dev - name: Tests run: | xmake f -a ${{ matrix.arch }} xmake run demo xmake f -m debug -a ${{ matrix.arch }} xmake -r xmake run demo xmake f --micro=y -a ${{ matrix.arch }} xmake -r xmake run demo xmake f --small=y -m debug -a ${{ matrix.arch }} xmake -r xmake run demo tbox-1.7.6/.gitignore000077500000000000000000000004131467117505400145040ustar00rootroot00000000000000*.a *.b *.o *.exe *.obj *.dll *.lib *.out *.suo *~ *.swp *.swo *.bak *.orig *.pdb *.idb *.ilk *.gcov *.gcda *.gcno *.gch *.gch.d *.stackdump *.manifest .ccache .xmake build .svn .DS_Store cscope.* gmon.out tags Doxyfile .vscode .idea CMakeLists.txt Makefile makefile tbox-1.7.6/CHANGELOG.md000066400000000000000000000436651467117505400143420ustar00rootroot00000000000000# Changelog ([中文](#中文)) ## master (unreleased) ## v1.7.6 ### New features * Support cosmocc toolchain ### Changes * Implement copy symlinks on windows ## v1.7.5 ### Changes * Improve to check interfaces * Improve process to output same pipes ## v1.7.4 ### New features * Add Haiku support * Add tb_file_fscase ### Changes * Improve wasm support * Improve to kill processes * Improve xmake.sh ### Bugs fixed * Fix setenv for msys/mingw * Fix compile error for mingw * Fix tb_buffer_memsetp ## v1.7.3 ### Changes * Improve support for xp and mingw * Improve configure to support debian package better ## v1.7.2 ### New features * [#201](https://github.com/tboox/tbox/pull/201): Add xmake.sh ### Changes * Improve path for windows, support UNC and dos device path ### Bugs Fixed * [#199](https://github.com/tboox/tbox/issues/199): Fix tb_strcmp ## v1.7.1 ### New features * [#190](https://github.com/tboox/tbox/pull/190): Add fs watcher * Add `tb_file_touch` api ### Changes * Support wasm * Support arm64 for windows * Improve tb_file_info to detect symlink * Improve tb_file_copy to support symlink * Improve tb_directory_copy to support symlink ## v1.6.9 ### Changes * Improve bloom filter * Improve random for msvc ### Bugs Fixed * [#187](https://github.com/tboox/tbox/issues/187): Fix sort and iterator bug ## v1.6.8 ### Changes * Add riscv32/riscv64/sh4/sparc support * Improve path support * Add peer name for socket ### Bugs Fixed * [#178](https://github.com/tboox/tbox/issues/178): Fix coroutine on windows/x86 ## v1.6.7 ### Changes * Support coroutine for mingw * Improve process poller to support to wait more processes on windows ### Bugs Fixed * [#175](https://github.com/tboox/tbox/issues/175): Fix coroutine crash on windows * Fix some compilation errors ## v1.6.6 ### New features * Support *BSD system, e.g. FreeBSD .. ### Changes * Support to change the current directory for process * Support stdin for creating process * Fix some compilation errors for mingw ## v1.6.5 ### New features * [#112](https://github.com/tboox/tbox/issues/112): Support unix socket,thanks [@Codehz](https://github.com/codehz) * Support to wait pipe, socket and process in coroutine and poller at same time ### Changes * improve uuid and improve uuid v4 * support msys/mingw and cygwin/gcc toolchains ## v1.6.4 ### New features * [#70](https://github.com/tboox/tbox/issues/70): Add `tb_stream_init_from_sock_ref()` to open a given socket as stream * Add stdfile api to read/write stdin, stdout and stderr. * [#81](https://github.com/tboox/tbox/issues/81): Add set/get thread/process cpu affinity * Add filelock api * Add anonymous and named pipe ### Changes * Optimize queue_buffer module * Improve stream interfaces * Improve charset encoding and add ANSI support * Improve atomic and add c11-like atomic apis * Improve spinlock * Support to redirect process output to pipe * Uses virtual memory for coroutine stack * Improve openssl/mbedtls for https ## v1.6.3 ### New features * [#24](https://github.com/tboox/tbox/issues/24): Support IOCP for coroutine on windows ### Changes * Move docs directory to tbox-docs repo * Support tinyc compiler * Remove deprecated module (asio), please use coroutine module * Improve memory for container * Help valgrind to understand coroutines ### Bugs fixed * Fix the charset problem of envirnoment variables * Fix process exit bug * Fix setenv empty value crash * Fix coroutine.sleep bug * Fix windows root path bug * Fix thread local memory leak * Fix context bug for coroutine * Fix `tb_vsnprintf` overflow * [#43](https://github.com/tboox/tbox/issues/43): Fix read dns server and stream bug ## v1.6.2 ### New features * Add ping demo for network ### Changes * Modify license to Apache License 2.0 * Rename `--smallest=y|n` option to `--small=y|n` * Support stat64 * Improve copy speed and fix permissions for `tb_file_copy` * Improve path operation for posix platform * Improve socket interfaces and support icmp ### Bugs fixed * Fix create file mode to 0644 * Fix file and directory path bug * Fix remove directory with dead symbol link failed * Fix remove readonly file failed * [#34](https://github.com/tboox/tbox/issues/34): Fix cache time and coroutine sleep bug * [#35](https://github.com/tboox/tbox/issues/35): Fix epoll bug with the edge trigger mode ## v1.6.1 ### New features * Support coroutine context switch for mips * Add `__tb_thread_local__` keyword macro * Add `--micro=y|n` option to compiling micro library (~64K) for the embed system * Add `tb_addrinfo_addr` and `tb_addrinfo_name` interfaces * Add stackless coroutine * Add semaphone and lock for the stackless coroutine ### Changes * Optimize io scheduler for coroutine, cache events for poller * Add c11 `_Static_assert` * Remove some deprecated interfaces for hash and platform ## v1.6.0 ### New features * Support make command and compile directly without xmake * Add switch context interfaces into platform module * Add coroutine module (supports i386, x86_64, arm, arm64, mips ..) * Add simple http server demo using coroutine * Add simple spider using coroutine * Add io poller interfaces(with epoll, poll, kqueue, select) * Support mbedtls ssl library * All io modules(stream, socket, http, ..) support coroutine mode * Provide lock, semaphone and channel for coroutine ### Changes * Optimize and rewrite thread local store module * Modify thread interfaces * Mark the asio module as deprecated * Optimize exception interfaces ### Bugs fixed * Fix some warning and errors for compiler * Fix some thread bugs * Fix parse bplist uid type ## v1.5.3 ### New features * Add wait multi-processes interface * Add uuid generator * Add hash library module * Add `__tb_deprecated__` keyword and option ### Changes * Move some utils interfaces to the hash module * Rewrite random generator ### Bugs fixed * Fix stdout compatibility issue for vs2015 * Fix process arguments length limit ## v1.5.2 ### New features * Add smallest configure option * Add process operation interfaces ### Changes * Improve envirnoment interfaces * Modify xmake.lua for supporting xmake v2.x ### Bugs fixed * Fix ltimer bug * Fix asio memory leaks bug * Fix asio httpd response bug on linux * Fix path bug for windows ## v1.5.1 ### New features * Add automaticlly check libc interfaces * Support custom allocator * Add trace for allocator in the debug mode * Add `static_pool` module * Add stream interfaces for reading all data to string * Add adler32 hash algorithm * Add `tb_memmem` interface * Add regex module with pcre, pcre2 or posix regex ### Changes * Optimize stream and support read/write character device file * Modify `tb_init` api and support allocator arguments * Improve memory manager and use the allocator mode * Redefine `assert` and will abort for debug mode ### Bugs fixed * Fix some bugs for android * Fix seek bug for stream

# 更新日志 ## master (开发中) ## v1.7.6 ### 新特性 * 增加对 cosmocc 工具链支持 ### 改进 * 改进 copyfile 支持,在 windows 实现对 symlinks 的复制 ## v1.7.5 ### 改进 * 改进接口检测 * 改进 windows 进程输出,支持同时输出到同一个管道 ## v1.7.4 ### 新特性 * 添加 Haiku 支持 * 添加 tb_file_fscase 接口判断文件大小写敏感 ### 改进 * 改进 wasm 支持 * 改进退出子进程 * 改进 xmake.sh ### Bugs 修复 * 修复 msys/mingw 下 setenv 设置问题 * 修复 mingw 编译错误 * 修复 tb_buffer_memsetp ## v1.7.3 ### 改进 * 改进对 xp 和 mingw 的支持 * 改进 configure 构建脚本,更好的支持 debian 打包 ## v1.7.2 ### 新特性 * [#201](https://github.com/tboox/tbox/pull/201): 添加 xmake.sh ### 改进 * 改进 windows 下根路径处理,支持 UNC 和 dos 设备路径格式 ### Bugs 修复 * [#199](https://github.com/tboox/tbox/issues/199): 修复 tb_strcmp ## v1.7.1 ### 新特性 * [#190](https://github.com/tboox/tbox/pull/190): 添加文件系统状态监视器 * 添加 `tb_file_touch` 接口 ### 改进 * 支持 wasm * 支持 arm64 windows * 改进 tb_file_info,支持判断符号链接 * 改进 tb_file_copy 支持符号链接 * 改进 tb_directory_copy 支持符号链接 ## v1.6.9 ### 改进 * 改进 bloom filter * 改进 windows/msvc 下 random 实现 ### Bugs 修复 * [#187](https://github.com/tboox/tbox/issues/187): 修复排序和迭代器问题 ## v1.6.8 ### 改进 * 添加 riscv32/riscv64/sh4/sparc 架构支持 * 改进路径支持 * 为 socket 添加 peer name 接口 ### Bugs 修复 * [#178](https://github.com/tboox/tbox/issues/178): 修复协程在 windows/x86 上栈溢出问题 ## v1.6.7 ### 改进 * 改进协程,增加对 mingw 支持 * 改进 process poller 支持在 windows 上等待更多进程 ### Bugs 修复 * [#175](https://github.com/tboox/tbox/issues/175): 修复协程在 windows 上崩溃 * 修复一些编译问题 ## v1.6.6 ### 新特性 * 支持*BSD系统,例如:FreeBSD ### 改进 * 创建进程支持修改处理当前工作目录 * 创建禁止支持 stdin 重定向输入 * 修复一些 mingw 上的编译错误 ## v1.6.5 ### 新特性 * [#112](https://github.com/tboox/tbox/issues/112): 新增unix socket支持,感谢[@Codehz](https://github.com/codehz)的贡献 * 在协程和poller中支持同时等待和调度socket,pipe io和process ### 改进 * 改进uuid生成,实现uuid v4 * 支持msys/mingw和cygwin/gcc上编译 ## v1.6.4 ### 新特性 * [#70](https://github.com/tboox/tbox/issues/70): 添加`tb_stream_init_from_sock_ref()`接口去直接打开一个socket作为stream去读取数据。 * 添加stdfile接口去读写stdin, stdout和stderr。 * [#81](https://github.com/tboox/tbox/issues/81): 添加对进程和线程的cpu亲缘性设置和获取 * 添加filelock文件锁跨平台api接口 * 添加匿名管道,命名管道支持 ### 改进 * 优化queue_buffer模块 * 改进stream接口实现 * 改进字符集编码转换,以及增加对ANSI编码的支持 * 改进原子操作,并增加c11风格原子接口 * 改进spinlock实现 * 新增进程输出重定向到管道 * 针对协程栈使用虚拟内存 * 改进基于openssl/mbedtls的https访问 ## v1.6.3 ### 新特性 * [#24](https://github.com/tboox/tbox/issues/24): 针对windows平台下的协程处理,增加IOCP支持 ### 改进 * 移除docs目录,放置到独立tbox-docs仓库,减少tbox.zip包大小 * 支持tinyc编译器 * 移除被废弃的模块(asio模块,先用coroutine代替) * 精简优化容器库内存资源使用 * 帮助valgrind更好的理解coroutine ### Bugs修复 * 修复windows环境变量的中文编码问题 * 修复后台进程退出问题 * 修复设置环境变量值为空时的崩溃问题 * 修复协程sleep超时覆写数据的bug * 修复windows根路径问题 * 修复tls线程存储内存泄露问题 * 修复context切换问题 * 修复`tb_vsnprintf`栈溢出问题 * [#43](https://github.com/tboox/tbox/issues/43): 修复读取dns服务器以及stream读取bug ## v1.6.2 ### 新特性 * 增加ping测试程序 ### 改进 * 修改license,使用更加宽松的Apache License 2.0 * 重命名`--smallest=y|n`选项到`--small=y|n` * 使用`stat64`支持大文件信息获取 * 改进`tb_file_copy`,更加快速的文件copy,并且修复copy后文件权限丢失问题 * 改进posix平台下的路径操作 * 改进socket初始化接口,支持icmp协议 ### Bugs修复 * 修复创建文件权限不对问题 * 修复文件和目录路径问题 * 修复无法移除带有无效软链的目录问题 * 修复无法移除只读文件问题 * [#34](https://github.com/tboox/tbox/issues/34): 修复缓存时间和协程sleep不准问题 * [#35](https://github.com/tboox/tbox/issues/35): 修复epoll边缘触发模式下,centos上检测连接关闭失效问题 ## v1.6.1 ### 新特性 * 针对协程上下文切换,支持mips架构 * 添加`__tb_thread_local__`关键字宏 * 添加 `--micro=y|n` 选项,实现极小编译,针对嵌入式平台,编译tbox微内核(~64K) * 添加 `tb_addrinfo_addr` and `tb_addrinfo_name` 接口 * 添加stackless协程,更加轻量的协程支持,每个协程只占用几十个bytes,同时支持io调度 * 针对stackless协程,增加lock和semaphone支持 ### 改进 * 为协程优化io调度器,缓存poller轮询等待,减少频繁重复调用epoll_ctl, kevent等系统接口 * 添加对c11关键字`_Static_assert`的支持 * 针对hash和platform模块,移除一些废弃的接口 ## v1.6.0 ### 新特性 * 支持make进行直接编译(会去自动下载xmake进行构建) * 在平台库中,添加切换context上下文接口(参考boost.context实现原理进行重写,并对部分架构进行优化) * 新增跨平台协程模块(支持i386, x86_64, arm, arm64, mips),提供更加易用的高性能并发编程模式 * 新增基于协程的各种服务器开发实例(包括:简单轻量的http服务器,爬虫。。) * 新增poller轮询器接口,实现对epoll, poll, kqueue, select的封装,逐步取代老的aiop接口 * 新增mbedtls ssl库接口支持,目前已支持:openssl, polarssl, mbedtls * tbox所有stream, socket, http, dns, ssl 等io相关操作,原生支持协程模式,并且可以在线程和协程间随意切换 * 为协程提供lock, semaphone, channel模块 ### 改进 * 优化和重构线程局部存储TLS模块 * 修改部分线程接口 * asio模块被标记为废弃接口,下个版本将会被移除,逐步使用协程模式来实现异步io开发 * 优化异常捕获接口 ### Bugs修复 * 修复一些编译警告和错误 * 修复一些线相关bug * 修复bplist中解析uid类型失败问题 ## v1.5.3 ### 新特性 * 增加同时等待多个进程接口 * 增加uuid生成器 * 增加hash库模块 * 添加`__tb_deprecated__`关键字以及配置选项 ### 改进 * 移动部分utils接口到hash模块 * 重写random生成器 ### Bugs修复 * 修复stdout在vs2015以上版本的兼容性问题 * 修复进程参数长度限制 ## v1.5.2 ### 新特性 * 增加smallest参数配置选项,实现一键配置最小化编译,禁用所有扩展模块和依赖库 * 增加进程创建和控制接口 ### 改进 * 增强环境变量设置接口 * 修改xmake.lua支持最新版xmake v2.x, 简化编译配置 ### Bugs修复 * 修复ltimer定时器不准问题 * 修复asio部分内存泄露问题 * 修复asio/httpd在linux下keepalive模式,响应很慢问题 * 修复windows下路径处理的一些bug ## v1.5.1 ### 新特性 * 自动检测所有系统libc接口,优先使用系统版本 * 支持自定义内存分配器,并且能够在debug模式下,获取每次分配的代码位置信息,用于自定义追踪 * 增加轻量级`static_pool`来维护整块buffer的内存分配,适合局部管理部分内存,pool虽然也能维护,但是底层基于`large_pool`,比较重量级,适合全局管理内存 * 增加stream快速读取全部数据到string的接口 * 增加adler32 hash算法 * 增加`tb_memmem`接口 * 采用pcre/pcre2/posix regex实现正则表达式库 ### 改进 * 优化stream,支持对字符设备文件的读写 * 修改`tb_init`接口,增加allocator自定义内存分配器参数,实现用户的侵入式内存管理 * 重构内存管理,完全采用分配器allocator模式,可以灵活切换内存管理,支持原生系统内存、静态buffer内存、内存池等各种分配方式 * 重定义assert,debug模式遇到assert直接abort执行 ### Bugs修复 * 修复android下的一些bug * 修复stream的seek问题 ## v1.5.0 ### 新特性 * 增加跨平台环境变量操作接口 ### 改进 * 重建整个编译架构,采用xmake跨平台自动构建工具进行构建。。 * 优化.pkg的依赖包机制,支持依赖库和接口的自动检测,针对libc、libm优先使用自动检测到的系统库接口实现,如果当前平台没有实现则使用tbox的自己实现版本,使得最大化性能和跨平台性。。 * 完善和优化路径操作,增加相对路径、绝对路径的相互转换 ### Bugs修复 * 修复strlcpy等一些libc接口的实现bug ## v1.4.8 ### 新特性 * 新增路径操作接口,支持相对路径、绝对路径相互转换 ### 改进 * 重建整个makefile架构,采用`*.pkg`依赖包模式模块化对第三方库的依赖,降低耦合 * 默认编译配置可以自动探测当前平台支持的依赖包,注:所有依赖包都是可选的,如果要最小化编译,可以完全禁用 * 编译生成的所有库和头文件,也都安装成独立`*.pkg`格式,方便集成到其他开发平台,也方便copy * 增强object路径解析接口,支持json, xml宏路径解析,并增加实用json解析工具:jcat * 实现通用ipaddr结构,统一接口,全面支持ipv6/ipv4,stream/http的url也完全支持ipv6格式解析 * 重命名hash为`hash_map`,并新增`hash_set`容器 ## v1.4.7 ### 改进 * 增强fixed16定点类型的接口,优化部分接口性能,调试模式下增加更多的溢出检测 * 优化整数平方根的实现,增加对64位整数平方根的快速计算 ### Bugs修复 * 修复string空字符串bug * 修复windows下asio的一些bug * 修复一些编译问题 ## v1.4.7_rc1 ### 新特性 * 增加asio模块,支持各种异步socket/file操作,支持异步dns、ssl(依赖polarssl/openssl)、http * 增加http cookie支持,完善http客户端协议 * 增加sql数据库模块,依赖sqlite3/mysql * 增加object模块 * 新增min/max heap容器,新增`list_entry`、`single_list_entry`等外置轻量链表实现,和`list`、`single_list`不同的是,不需要维护内部内存,而且更加灵活,新增bloom_filter * 新增remove、walk、count、for等常用算法支持 * 新增线程池、定时器、信号量、自旋锁、atomic64等常用系统操作 * 新增http服务器、http爬虫、http下载器等实用性demo ### 改进 * 重构stream模块,并新增`async_stream`、`async_transfer`、`transfer_pool`等新特性。 * 优化和完善libc、libm的接口 * 重构整个内存管理架构,完善内存检测的支持,优化内存使用和效率 ### Bugs修复 * 修复和优化xml解析模块 tbox-1.7.6/CODE_OF_CONDUCT.md000066400000000000000000000134571467117505400153240ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [waruqi@gmail.com]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org # Contributor Covenant行为准则 # 参与者公约 ## 我们的保证 为了促进一个开放透明且友好的环境,我们作为贡献者和维护者保证:无论年龄、种族、民族、性别认同和表达(方式)、体型、身体健全与否、经验水平、国籍、个人表现、宗教或性别取向,参与者在我们项目和社区中都免于骚扰。 ## 我们的标准 有助于创造正面环境的行为包括但不限于: * 使用友好和包容性语言 * 尊重不同的观点和经历 * 耐心地接受建设性批评 * 关注对社区最有利的事情 * 友善对待其他社区成员 身为参与者不能接受的行为包括但不限于: * 使用与性有关的言语或是图像,以及不受欢迎的性骚扰 * 捣乱/煽动/造谣的行为或进行侮辱/贬损的评论,人身攻击及政治攻击 * 公开或私下的骚扰 * 未经许可地发布他人的个人资料,例如住址或是电子地址 * 其他可以被合理地认定为不恰当或者违反职业操守的行为 ## 我们的责任 项目维护者有责任为「可接受的行为」标准做出诠释,以及对已发生的不被接受的行为采取恰当且公平的纠正措施。 项目维护者有权利及责任去删除、编辑、拒绝与本行为标准有所违背的评论 (comments)、提交 (commits)、代码、wiki 编辑、问题 (issues) 和其他贡献,以及项目维护者可暂时或永久性的禁止任何他们认为有不适当、威胁、冒犯、有害行为的贡献者。 ## 使用范围 当一个人代表该项目或是其社区时,本行为标准适用于其项目平台和公共平台。 代表项目或是社区的情况,举例来说包括使用官方项目的电子邮件地址、通过官方的社区媒体账号发布或线上或线下事件中担任指定代表。 该项目的呈现方式可由其项目维护者进行进一步的定义及解释。 ## 强制执行 可以通过[waruqi@gmail.com],来联系项目团队来举报滥用、骚扰或其他不被接受的行为。 任何维护团队认为有必要且适合的所有投诉都将进行审查及调查,并做出相对应的回应。项目小组有对事件回报者有保密的义务。具体执行的方针近一步细节可能会单独公布。 没有切实地遵守或是执行本行为标准的项目维护人员,可能会因项目领导人或是其他成员的决定,暂时或是永久地取消其参与资格。 ## 来源 本行为标准改编自[贡献者公约][主页],版本 1.4 可在此观看https://www.contributor-covenant.org/zh-cn/version/1/4/code-of-conduct.html [主页]: https://www.contributor-covenant.org tbox-1.7.6/CONTRIBUTING.md000066400000000000000000000064441467117505400147540ustar00rootroot00000000000000# Contributing If you discover issues, have ideas for improvements or new features, or want to contribute a new module, please report them to the [issue tracker][1] of the repository or submit a pull request. Please, try to follow these guidelines when you do so. ## Issue reporting * Check that the issue has not already been reported. * Check that the issue has not already been fixed in the latest code (a.k.a. `master`). * Be clear, concise and precise in your description of the problem. * Open an issue with a descriptive title and a summary in grammatically correct, complete sentences. * Include any relevant code to the issue summary. ## Pull requests * Use a topic branch to easily amend a pull request later, if necessary. * Write good commit messages. * Use the same coding conventions as the rest of the project. * Ensure your edited codes with four spaces instead of TAB. * Please commit code to `dev` branch and we will merge into `master` branch in feature * Before adding new features and new modules, please go to issues to submit the relevant feature description first # 贡献代码 如果你发现一些问题,或者想新增或者改进某些新特性,或者想贡献一个新的模块 那么你可以在[issues][1]上提交反馈,或者发起一个提交代码的请求(pull request). ## 问题反馈 * 确认这个问题没有被反馈过 * 确认这个问题最近还没有被修复,请先检查下 `master` 的最新提交 * 请清晰详细地描述你的问题 * 如果发现某些代码存在问题,请在issue上引用相关代码 ## 提交代码 * 请先更新你的本地分支到最新,再进行提交代码请求,确保没有合并冲突 * 编写友好可读的提交信息 * 请使用与工程代码相同的代码规范 * 请提交代码到`dev`分支,如果通过,我们会在特定时间合并到`master`分支上 * 为了规范化提交日志的格式,commit消息,不要用中文,请用英文描述 * 增加新特性和新模块之前,请先到issues提交相关特性说明,经过讨论评估确认后,再进行相应的代码提交,避免做无用工作 ## 编码规范 代码需要符合tbox的编码风格,保证整体风格一致,这样可读性会更好,也更容易维护,下面列举一些风格描述。 * 空格缩进、填充,4字符宽度,不允许出现任意tab字符 * 换行符'\n',不要用'\r\n' * 文件utf8编码,不允许其他编码格式,例如:gbk * 全英文注释,public接口注释采用doxygen风格 * 类unix命名规范:小写 + 下划线,例如:`aaa_bb_cc`,不允许任何大写字符 * 接口名、宏定义等必须带:`tb_`, `TB_`前缀 * 需要使用tbox提供的基础类型,例如:`tb_size_t` * if, while, for等关键字之后,带一个空格,例如:`if ()`, `for (; ;)` * 如果if, for的body只有一行代码,不需要写大括号 * {}块,换行对称 * 局部变量定义不需要遵循c89风格,定义位置尽量靠近实际使用的地方 * 函数取参,返回值处理,需要有assert检测 * 宏定义大写,其他都小写 * 除非必要,尽量使用`tb_size_t`, `tb_long_t`类型,而不是`tb_int_t` * 接口定义、接口实现、宏定义、全局变量、include等布局风格必须一致,风格可参考实际代码 [1]: https://github.com/tboox/tbox/issues tbox-1.7.6/LICENSE.md000077500000000000000000000342301467117505400141240ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2009-present TBOOX Open Source Group Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ------------------------------------------------------------------------------- ## SUBCOMPONENTS The TBOX project contains subcomponents with separate copyright notices and license terms. Your use of the source code for the these subcomponents is subject to the terms and conditions of the following licenses. #### Boost Software License Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For src/tbox/platform/arch/{arm,arm64,mips,x86,x64}/context.{S,asm}: ``` /* Copyright Oliver Kowalke 2009. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ ``` #### ZLib License Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler For src/tbox/hash/adler32.c: ``` /* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ ``` tbox-1.7.6/NOTICE.md000077500000000000000000000042071467117505400140240ustar00rootroot00000000000000The Treasure Box Library Copyright 2009-present The TBOOX Open Source Group This product includes software developed by The TBOOX Open Source Group (https://tboox.org/). ------------------------------------------------------------------------------- This product contains a modified portion of 'boost.context', a coroutine context implementation for assembler code, which can be obtained at: * LICENSE: * http://www.boost.org/LICENSE_1_0.txt (Boost Software License 1.0) * HOMEPAGE: * http://www.boost.org This product contains a modified portion of 'zlib.adler32', compute the Adler-32 checksum of a data stream, which can be obtained at: * LICENSE: * pkg/zlib.pkg/LICENSE.md (Zlib License) * HOMEPAGE: * http://zlib.net/ This product optionally depends on 'pcre', a library of functions to support regular expressions, which can be obtained at: * LICENSE: * pkg/pcre.pkg/LICENSE.md (BSD License) * HOMEPAGE: * http://www.pcre.org/ This product optionally depends on 'pcre2', a library of functions to support regular expressions, which can be obtained at: * LICENSE: * pkg/pcre2.pkg/LICENSE.md (BSD License) * HOMEPAGE: * http://www.pcre.org/ This product optionally depends on 'mbedtls', an open source, portable, easy to use, readable and flexible SSL library, which can be obtained at: * LICENSE: * pkg/mbedtls.pkg/LICENSE.md (Apache License 2.0) * HOMEPAGE: * https://tls.mbed.org/ This product optionally depends on 'polarssl', an open source, portable, easy to use, readable and flexible SSL library, which can be obtained at: * LICENSE: * pkg/polarssl.pkg/LICENSE.md (GPL 2.0) * HOMEPAGE: * https://tls.mbed.org/ This product optionally depends on 'openssl', a TLS/SSL and crypto library, which can be obtained at: * LICENSE: * pkg/openssl.pkg/LICENSE.md (OpenSSL License and SSLeay license) * HOMEPAGE: * https://www.openssl.org/ This product optionally depends on 'sqlite3', a self-contained, high-reliability, embedded, full-featured, public-domain, SQL database engine, which can be obtained at: * LICENSE: * Public Domain * HOMEPAGE: * http://sqlite.org/ tbox-1.7.6/README.md000077500000000000000000000224251467117505400140020ustar00rootroot00000000000000
github-ci github-ci github-ci github-ci Github All Releases
license Reddit Gitter Telegram QQ Donate

A glib-like cross-platform C library

## Supporting the project Support this project by becoming a sponsor. Your logo will show up here with a link to your website. 🙏 [[Become a sponsor](https://docs.tboox.org/#/about/sponsor)] ## Introduction ([中文](/README_zh.md)) TBOX is a glib-like cross-platform C library that is simple to use yet powerful in nature. The project focuses on making C development easier and provides many modules (.e.g stream, coroutine, regex, container, algorithm ...), so that any developer can quickly pick it up and enjoy the productivity boost when developing in C language. It supports the following platforms: Windows, Macosx, Linux, Android, iOS, *BSD and etc. And it provides many compiling options using [xmake](https://github.com/xmake-io/xmake): * Release: Disable debug information, assertion, memory checking and enable optimization. * Debug: Enable debug information, assertion, memory checking and disable optimization. * Small: Disable all extensional modules and enable space optimization. * Micro: compiling micro library (~64K) for the embed system. If you want to know more, please refer to: [Documents](https://docs.tboox.org/#/getting_started), [Github](https://github.com/tboox/tbox) and [Gitee](https://gitee.com/tboox/tbox) ## Features #### The stream library - Supports file, data, http and socket source - Supports the stream filter for gzip, charset and... - Implements stream transfer - Implements the static buffer stream for parsing data - Supports coroutine and implements asynchronous operation #### The coroutine library - Provides high-performance coroutine switch - Supports arm, arm64, x86, x86_64 .. - Provides channel interfaces - Provides semaphore and lock interfaces - Supports io socket and stream operation in coroutine - Provides some io servers (http ..) using coroutine - Provides stackfull and stackless coroutines - Support epoll, kqueue, poll, select and IOCP - Support to wait pipe, socket and process in coroutine and poller at same time #### The database library - Supports mysql and sqlite3 database and enumerates data using the iterator mode #### The xml parser library - Supports DOM and SAX mode and Supports xpath #### The serialization and deserialization library - Supports xml, json, bplist, xplist, binary formats #### The memory library - Implements some memory pools for optimizing memory - Supports fast memory error detecting. it can detect the following types of bugs for the debug mode: - out-of-bounds accesses to heap and globals - use-after-free - double-free, invalid free - memory leaks #### The container library - Implements hash table, single list, double list, vector, stack, queue and min/max heap. Supports iterator mode for algorithm #### The algorithm library - Uses the iterator mode - Implements find, binary find and reverse find algorithm - Implements sort, bubble sort, quick sort, heap sort and insert sort algorithm - Implements count, walk items, reverse walk items, for_all and rfor_all #### The network library - Implements dns(cached) - Implements ssl(openssl, polarssl, mbedtls) - Implements http - Implements cookies - Supports ipv4, ipv6 - Supports coroutine #### The platform library - Implements timer, fast and low precision timer - Implements atomic and atomic64 operation - Implements spinlock, mutex, event, semaphore, thread and thread pool - Implements file, socket operation - Implements poller using epoll, poll, select, kqueue ... - Implements switch context interfaces for coroutine #### The charset library - Supports utf8, utf16, gbk, gb2312, uc2 and uc4 - Supports big endian and little endian mode #### The zip library - Supports gzip, zlibraw, zlib formats using the zlib library if exists - Implements lzsw, lz77 and rlc algorithm #### The utils library - Implements base32, base64 encoder and decoder - Implements assert and trace output for the debug mode - Implements bits operation for parsing u8, u16, u32, u64 data #### The math library - Implements random generator - Implements fast fixed-point calculation, Supports 6-bits, 16-bits, 30-bits fixed-point number #### The libc library - Implements lightweight libc library interfaces, the interface name contains `tb_xxx` prefix for avoiding conflict - Implements strixxx strrxxx wcsixxx wcsrxxx interface extension - Optimizes some frequently-used interface, .e.g. memset, memcpy, strcpy ... - Implements `memset_u16`, `memset_u32`, `memset_u64` extension interfaces #### The libm library - Implements lightweight libm library interfaces, the interface name contains `tb_xxx` prefix for avoiding conflict - Supports float and double type #### The regex library - Supports match and replace - Supports global/multiline/caseless mode - Uses pcre, pcre2 and posix regex modules #### The hash library - Implements crc32, adler32, md5 and sha1 hash algorithm - Implements some string hash algorithms (.e.g bkdr, fnv32, fnv64, sdbm, djb2, rshash, aphash ...) - Implements uuid generator ## Projects Some projects using tbox: * [gbox](https://github.com/tboox/gbox) * [vm86](https://github.com/tboox/vm86) * [xmake](http://www.xmake.io) * [itrace](https://github.com/tboox/itrace) * [more](https://github.com/tboox/tbox/wiki/tbox-projects) ## Build (xmake) Please install xmake first: [xmake](https://github.com/xmake-io/xmake) ```console # build for the host platform $ cd ./tbox $ xmake # build for the mingw platform $ cd ./tbox $ xmake f -p mingw --sdk=/home/mingwsdk $ xmake # build for the iphoneos platform $ cd ./tbox $ xmake f -p iphoneos $ xmake # build for the android platform $ cd ./tbox $ xmake f -p android --ndk=xxxxx $ xmake # build for the linux cross-platform $ cd ./tbox $ xmake f -p linux --sdk=/home/sdk # --bin=/home/sdk/bin $ xmake ``` ## Build (xmake.sh) ```console $ ./configure $ make ``` ## Example ```c #include "tbox/tbox.h" int main(int argc, char** argv) { if (!tb_init(tb_null, tb_null)) return 0; tb_vector_ref_t vector = tb_vector_init(0, tb_element_str(tb_true)); if (vector) { tb_vector_insert_tail(vector, "hello"); tb_vector_insert_tail(vector, "tbox"); tb_for_all (tb_char_t const*, cstr, vector) { tb_trace_i("%s", cstr); } tb_vector_exit(vector); } tb_exit(); return 0; } ``` ## Technical Support You can also consider sponsoring us to get technical support services, [[Become a sponsor](https://docs.tboox.org/#/about/sponsor)] ## Contacts * Email:[waruqi@gmail.com](mailto:waruqi@gmail.com) * Homepage:[tboox.org](https://tboox.org) * Community:[/r/tboox on reddit](https://www.reddit.com/r/tboox/) * ChatRoom:[Chat on telegram](https://t.me/tbooxorg), [Chat on gitter](https://gitter.im/tboox/tboox?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) * QQ Group: 343118190(full), 662147501 * Wechat Public: tboox-os tbox-1.7.6/README_zh.md000077500000000000000000000310731467117505400145020ustar00rootroot00000000000000
github-ci github-ci github-ci github-ci Github All Releases
license Reddit Gitter Telegram QQ Donate

一个用c语言实现的跨平台开发库

## 项目支持 通过成为赞助者来支持该项目。您的logo将显示在此处,并带有指向您网站的链接。🙏 [[成为赞助商](https://docs.tboox.org/#/zh-cn/about/sponsor)] ## 简介 TBOX是一个用c语言实现的跨平台开发库。 针对各个平台,封装了统一的接口,简化了各类开发过程中常用操作,使你在开发过程中,更加关注实际应用的开发,而不是把时间浪费在琐碎的接口兼容性上面,并且充分利用了各个平台独有的一些特性进行优化。 这个项目的目的,是为了使C开发更加的简单高效。 目前支持的平台有: Windows, Macosx, Linux, Android, iOS, *BSD等等。 通过[xmake](https://github.com/xmake-io/xmake)支持各种编译模式: * Release: 正式版编译,禁用调试信息、断言,各种检测机制,启用编译器优化 * Debug: 调试模式,默认启用详细调试信息、断言、内存越界检测、内存泄漏、锁竞争分析等检测机制 * Small: 最小化编译,默认禁用所有扩展模块,启用编译器最小化优化 * Micro: 针对嵌入式平台,仅仅编译tbox微内核,仅提供最基础的跨平台接口,生成库仅64K左右(内置轻量libc接口实现) 如果你想了解更多,请参考:[在线文档](https://docs.tboox.org/#/zh-cn/getting_started), [Github](https://github.com/tboox/tbox)以及[Gitee](https://gitee.com/tboox/tbox)和[GitCode](https://gitcode.com/tboox/tbox)。 ## 特性 #### 流库 针对http、file、socket、data等流数据,实现统一接口进行读写,并且支持: 阻塞、非阻塞、异步 三种读写模式。 支持中间增加多层filter流进行流过滤,实现边读取,内部边进行解压、编码转换、加密等操作,极大的减少了内存使用。 主要提供以下模块: - `stream`:通用非阻塞流,用于一般的单独io处理,同时支持协程以实现异步传输。 - `transfer`:流传输器,维护两路流的传输。 - `static_stream`:针对静态数据buffer优化的静态流,用于轻量快速的数据解析。 #### 协程库 - 快速高效的协程切换支持 - 提供跨平台支持,核心切换算法参考boost,并且对其进行重写和优化,目前支持架构:x86, x86_64, arm, arm64, mips32 - 提供channel协程间数据通信支持,基于生产、消费者模型 - 提供信号量、协程锁支持 - socket、stream都模块原生支持协程,并且可在线程和协程间进行无缝切换 - 提供http、file等基于协程的简单服务器实例,只需几百行代码,就可以从socket开始写个高性能io服务器,代码逻辑比异步回调模式更加清晰 - 同时提供stackfull, stackless两种协程模式支持,stackless协程更加的轻量(每个协程只占用几十个bytes),切换更快(会牺牲部分易用性) - 支持epoll, kqueue, poll, select 和 IOCP - 在协程和poller中支持同时等待和调度socket,pipe io和process #### 数据库 - 统一并简化数据库操作接口,适配各种数据源,通过统一的url来自动连接打开支持的数据库,数据的枚举采用迭代器模型。 - 目前支持sqlite3以及mysql两种关系型数据库,也可自定义扩展使用其他关系型数据库。 #### xml库 - 针对xml提供DOM和SAX两种解析模式,SAX方式采用外部迭代模式,灵活性和性能更高,并且可以选择指定路径,进行解析。 - 解析过程完全基于stream,所以是高度流化的,可以实现边下载、边解压、边转码、边解析一条龙服务,使用较低的内存也可以解析大规模数据。 - 提供xml writer以支持对xml生成 #### 内存库 - 参考linux内核内存管理机制的实现,并对其进行各种改造和优化,所实现的TBOX独有的一整套内存池管理架构。 - 调试模式下,可以轻松检测并定位内存泄露、内存越界溢出、内存重叠覆盖等常见内存问题,并对整体内存的使用进行了统计和简要分析。 - 针对大块数据、小块数据、字符串数据进行了充分的利用,避免了大量外部碎片和内部碎片的产生。分配操作进行了各种优化,96%的情况下,效率都是在O(1)。 #### 容器库 - 提供哈希、链表、数组、队列、堆栈、最小最大堆等常用容器。 - 支持各种常用成员类型,在原有的容器期初上,其成员类型还可以完全自定义扩展。 - 所有容器都支持迭代器操作。 - 大部分容器都可以支持基于stream的序列化和反序列化操作。 #### 算法库 - 提供各种排序算法:冒泡排序、堆排序、快速排序、插入排序。 - 提供各种查找算法:线性遍历、二分法搜索。 - 提供各种遍历、删除、统计算法。 - 以迭代器为接口,实现算法和容器的分离,类似stl,但是c实现的,更加轻量。 #### 网络库 - 实现http客户端模块 - 实现cookies - 实现dns解析与缓存 - 实现ssl(支持openssl, polarssl, mbedtls) - 支持ipv4、ipv6 - 支持通过协程实现异步模式 #### 数学运算库 - 提供各种精度的定点运算支持 - 提供随机数生成器 #### libc库 - libc的一个轻量级实现,完全跨平台,并且针对不同架构进行了优化。 - 支持大部分字符串、宽字符串操作。 - 扩展字符串、宽字符串的各种大小写不敏感操作接口 - 扩展`memset_u16`、`memset_u32`等接口,并对其进行高度优化,尤其适合图形渲染程序 #### libm库 - libm部分接口的一个轻量级实现,以及对常用系统接口的封装。(目前只实现了部分,之后有时间会完全实现掉) - 扩展部分常用接口,增加对sqrt、log2等常用函数的整数版本计算,进行高度优化,不涉及浮点运算,适合嵌入式环境使用。 #### object库 - 轻量级类apple的CoreFoundation库,支持object、dictionary、array、string、number、date、data等常用对象,并且可以方便扩展自定义对象的序列化。 - 支持对xml、json、binary以及apple的plist(xplist/bplist)格式序列化和反序列化。 并且实现自有的binary序列化格式, 针对明文进行了简单的加密,在不影响性能的前提下,序列化后的大小比bplist节省30%。 #### 平台库 - 提供file、directory、socket、thread、time等常用系统接口 - 提供atomic、atomic64接口 - 提供高精度、低精度定时器 - 提供高性能的线程池操作 - 提供event、mutex、semaphore、spinlock等事件、互斥、信号量、自旋锁操作 - 提供获取函数堆栈信息的接口,方便调试和错误定位 - 提供跨平台动态库加载接口(如果系统支持的话) - 提供io轮询器,针对epoll, poll, select, kqueue进行跨平台封装 - 提供跨平台上下文切换接口,主要用于协程实现,切换效率非常高 #### 压缩库 - 支持zlib/zlibraw/gzip的压缩与解压(需要第三方zlib库支持)。 #### 字符编码库 - 支持utf8、utf16、gbk、gb2312、uc2、uc4 之间的互相转码,并且支持大小端格式。 #### 实用工具库 - 实现base64/32编解码 - 实现crc32、adler32、md5、sha1等常用hash算法 - 实现日志输出、断言等辅助调试工具 - 实现url编解码 - 实现位操作相关接口,支持各种数据格式的解析,可以对8bits、16bits、32bits、64bits、float、double以及任意bits的字段进行解析操作,并且同时支持大端、小端和本地端模式,并针对部分操作进行了优化,像static_stream、stream都有相关接口对其进行了封装,方便在流上进行快速数据解析。 - 实现swap16、swap32、swap64等位交换操作,并针对各个平台进行了优化。 - 实现一些高级的位处理接口,例如:位0的快速统计、前导0和前导1的快速位计数、后导01的快速位计数 - 实现单例模块,可以对静态对象、实例对象进行快速的单例封装,实现全局线程安全 - 实现option模块,对命令行参数进行解析,提供快速方便的命令行选项建立和解析操作,对于写终端程序还是很有帮助的 #### 正则表达式库 - 支持匹配和替换操作 - 支持全局、多行、大小写不敏感等模式 - 使用pcre, pcre2和posix正则库 ## 一些使用tbox的项目: * [gbox](https://github.com/tboox/gbox) * [vm86](https://github.com/tboox/vm86) * [xmake](http://www.xmake.io/cn) * [itrace](https://github.com/tboox/itrace) * [更多项目](https://github.com/tboox/tbox/wiki/%E4%BD%BF%E7%94%A8tbox%E7%9A%84%E5%BC%80%E6%BA%90%E5%BA%93) ## 使用 Xmake 编译 请先安装: [xmake](https://github.com/xmake-io/xmake) ```console # 默认直接编译当前主机平台 $ cd ./tbox $ xmake # 编译mingw平台 $ cd ./tbox $ xmake f -p mingw --sdk=/home/mingwsdk $ xmake # 编译iphoneos平台 $ cd ./tbox $ xmake f -p iphoneos $ xmake # 编译android平台 $ cd ./tbox $ xmake f -p android --ndk=xxxxx $ xmake # 交叉编译 $ cd ./tbox $ xmake f -p linux --sdk=/home/sdk #--bin=/home/sdk/bin $ xmake ``` ## 使用 xmake.sh 编译 ```console $ ./configure $ make ``` ## 例子 ```c #include "tbox/tbox.h" int main(int argc, char** argv) { if (!tb_init(tb_null, tb_null)) return 0; tb_vector_ref_t vector = tb_vector_init(0, tb_element_str(tb_true)); if (vector) { tb_vector_insert_tail(vector, "hello"); tb_vector_insert_tail(vector, "tbox"); tb_for_all (tb_char_t const*, cstr, vector) { tb_trace_i("%s", cstr); } tb_vector_exit(vector); } tb_exit(); return 0; } ``` ## 技术支持 你可以考虑赞助我们也获取技术支持服务,[[成为赞助商](https://docs.tboox.org/#/zh-cn/about/sponsor)] ## 联系方式 * 邮箱:[waruqi@gmail.com](mailto:waruqi@gmail.com) * 主页:[TBOOX开源工程](https://tboox.org/cn) * 社区:[Reddit论坛](https://www.reddit.com/r/tboox/) * 聊天:[Telegram群组](https://t.me/tbooxorg), [Gitter聊天室](https://gitter.im/tboox/tboox?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) * QQ群:343118190(满), 662147501 * 微信公众号:tboox-os tbox-1.7.6/configure000077500000000000000000004236161467117505400144360ustar00rootroot00000000000000#!/bin/sh # A script-only build utility like autotools # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http:##www.apache.org#licenses#LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Copyright (C) 2022-present, TBOOX Open Source Group. # # @author ruki # @homepage https://github.com/xmake-io/xmake.sh # #----------------------------------------------------------------------------- # some constants # xmake_sh_projectdir=$(X= cd -- "$(dirname -- "$0")" && pwd -P) xmake_sh_buildir="build" xmake_sh_version="1.0.5" xmake_sh_verbose=false xmake_sh_diagnosis=false xmake_sh_copyright="Copyright (C) 2022-present Ruki Wang, tboox.org, xmake.io." xmake_sh_makefile="${xmake_sh_projectdir}/makefile" #----------------------------------------------------------------------------- # some helper functions # raise() { echo "$@" 1>&2 ; exit 1 } vprint() { if "${xmake_sh_verbose}"; then echo "$@" fi } dprint() { if "${xmake_sh_diagnosis}"; then echo "$@" fi } # show and escape string instead of `echo -e`, because sh does not support it print() { printf "${@}\n" } wprint() { if "${xmake_sh_verbose}"; then printf "warning: ${@}\n" fi } # test empty string test_z() { if test "x${1}" = "x"; then return 0 fi return 1 } # test non-empty string test_nz() { if test "x${1}" != "x"; then return 0 fi return 1 } # test string is equal test_eq() { if test "x${1}" = "x${2}"; then return 0 fi return 1 } # test string is not equal test_nq() { if test "x${1}" != "x${2}"; then return 0 fi return 1 } string_toupper() { _ret=$(echo "$1" | tr '[a-z]' '[A-Z]') } string_tolower() { _ret=$(echo "$1" | tr '[A-Z]' '[a-z]') } string_replace() { _ret=$(echo "$1" | sed "s/${2}/${3}/g") } # we avoid use `cut` command, because it's slow string_split() { local str="${1}" local sep="${2}" local idx="${3}" local oldifs="${IFS}" IFS="${sep}" set -- ${str} if test_nz "${idx}"; then case "${idx}" in 1) _ret="$1";; 2) _ret="$2";; 3) _ret="$3";; 4) _ret="$4";; 5) _ret="$5";; 6) _ret="$6";; esac else _ret="$1" _ret2="$2" _ret3="$3" _ret4="$4" _ret5="$5" _ret6="$6" fi IFS="${oldifs}" } # does contain sub-string? # e.g. # str="src/*.cpp" # string_contains "$str" "src" string_contains() { case "${1}" in *${2}*) return 0;; *) return 1;; esac return 1 } # does contain "*"? string_contains_star() { case "${1}" in *\**) return 0;; # bash *'*'*) return 0;; # csh *) return 1;; esac return 1 } # does contain "**"? string_contains_star2() { case "${1}" in *\*\**) return 0;; # bash *'**'*) return 0;; # csh *) return 1;; esac return 1 } # does startswith sub-string? # e.g. # str="src/*.cpp" # string_startswith "$str" "src" string_startswith() { case "${1}" in ${2}*) return 0;; *) return 1;; esac return 1 } # duplicate characters # e.g. string_dupch 10 "." => ........... string_dupch() { local count=${1} local ch=${2} printf %${count}s | tr " " "${ch}" } # replace file content _io_replace_file() { local infile="${1}" local outfile="${2}" local patterns="${3}" sed "/./ {${patterns}}" "${infile}" > "${outfile}" } # try remove file or directory _os_tryrm() { if test -f "${1}"; then rm "${1}" elif test -d "${1}"; then rm -r "${1}" fi } # get temporary file # https://github.com/xmake-io/xmake/issues/5464 _os_tmpfile() { _ret=$(mktemp "${TMPDIR-/tmp}/tmp.XXXXXXXX") } # try run program _os_runv() { if ${xmake_sh_diagnosis}; then ${@} else ${@} >/dev/null 2>&1 fi local ok=$? if test "${ok}" -ne "0"; then return 1 fi return 0 } # try run program and get output _os_iorunv() { _os_tmpfile local tmpfile="${_ret}" ${@} >"${tmpfile}" 2>&1 local ok=$? if test "${ok}" -ne "0"; then _ret="" else local result=$(cat "${tmpfile}") _ret="${result}" fi _os_tryrm "${tmpfile}" } # find file in the given directory # e.g. _os_find . xmake.sh _os_find() { local dir="${1}" local name="${2}" local depth="${3}" if test_nz "${depth}"; then if is_host "macosx"; then _ret=$(find "${dir}" -depth "${depth}" -type f -name "${name}") else _ret=$(find "${dir}" -maxdepth "${depth}" -mindepth "${depth}" -type f -name "${name}") fi else _ret=$(find "${dir}" -type f -name "${name}") fi } # get date, "%Y%m%d%H%M" -> 202212072222 # Use deterministic timestamp from SOURCE_DATE_EPOCH if available # https://reproducible-builds.org/docs/source-date-epoch/ _os_date() { if test_z "${SOURCE_DATE_EPOCH}"; then _ret=$(date +"${1}") elif is_host "macosx" "freebsd" "bsd"; then _ret=$(date -u -r "$SOURCE_DATE_EPOCH" +"${1}") else _ret=$(date -u -d "@$SOURCE_DATE_EPOCH" +"${1}") fi } # we avoid use `basename`, because it's slow path_filename() { local path="${1}" if test_eq "${path}" "/"; then _ret="/" else _ret="${path##*/}" fi } path_extension() { path_filename "${1}"; local filename="${_ret}" _ret=".${filename##*.}" } path_basename() { path_filename "${1}"; local filename="${_ret}" _ret="${filename%.*}" } # we avoid use `dirname -- ${1}`, because it's too slow path_directory() { local path="${1}" if test_z "${path}"; then raise "invalid empty path in path_directory()." fi path="${path%/}" local dir="${path%/*}" if string_startswith "${path}" "/"; then if test_z "${dir}"; then dir="/" fi else dir="${dir#/}" if test_z "${dir}"; then dir="." fi fi _ret="${dir}" } # e.g. path_filename_fromdir "/tmp/file" "/tmp" -> "file" path_filename_fromdir() { _ret="${1#${2}/}" } path_is_absolute() { if string_startswith "${1}" "/"; then return 0 fi return 1 } # get relative path, e.g $(path_relative ${rootdir} ${absolute_path}` path_relative() { local source="${1}" local target="${2}" if test_z "${source}" || test_z "${target}"; then raise "invalid empty path in path_relative()" fi # patch missing "./" source=${source#./} source=${source#.} target=${target#./} target=${target#.} if test_z "${source}"; then _ret="${target}" return fi # find common path local result="" local common_part=$source while test_eq "${target#$common_part}" "${target}"; do # no match, means that candidate common part is not correct # go up one level (reduce common part) path_directory "${common_part}"; common_part="${_ret}" # and record that we went back, with correct / handling if test_z "${result}"; then result=".." else result="../${result}" fi done if test_eq "${common_part}" "/"; then # special case for root (no common path) result="${result}/" fi # since we now have identified the common part, # compute the non-common part local forward_part="${target#$common_part}" # and now stick all parts together if test_nz "${result}" && test_nz "${forward_part}"; then result="${result}${forward_part}" elif test_nz "${forward_part}"; then result="${forward_part#*/}" fi # same directory? if test_z "${result}" && test_eq "${source}" "${target}"; then result="." fi _ret="${result}" } path_sourcekind() { local sourcekind="" case "${1}" in *.cpp) sourcekind="cxx";; *.cc) sourcekind="cxx";; *.c) sourcekind="cc";; *.ixx) sourcekind="cxx";; *.mm) sourcekind="mxx";; *.m) sourcekind="mm";; *.S) sourcekind="as";; *.s) sourcekind="as";; *.asm) sourcekind="as";; *) raise "unknown sourcekind for ${1}" ;; esac _ret="${sourcekind}" } path_toolname() { local toolname="" case "${1}" in *-gcc) toolname="gcc";; */gcc) toolname="gcc";; gcc) toolname="gcc";; gcc-*) toolname="gcc";; */gcc-*) toolname="gcc";; *-g++) toolname="gxx";; */g++) toolname="gxx";; g++) toolname="gxx";; g++-*) toolname="gxx";; */g++-*) toolname="gxx";; xcrun*clang++) toolname="clangxx";; xcrun*clang) toolname="clang";; *-clang++) toolname="clangxx";; */clang++) toolname="clangxx";; clang++) toolname="clangxx";; clang++-*) toolname="clangxx";; */clang++-*) toolname="clangxx";; *-clang) toolname="clang";; */clang) toolname="clang";; clang) toolname="clang";; clang-*) toolname="clang";; */clang-*) toolname="clang";; */emcc) toolname="emcc";; emcc) toolname="emcc";; */em++) toolname="emxx";; em++) toolname="emxx";; */cosmocc) toolname="cosmocc";; cosmocc) toolname="cosmocc";; */cosmoc++) toolname="cosmocxx";; cosmoc++) toolname="cosmocxx";; *-ar) toolname="ar";; */ar) toolname="ar";; ar) toolname="ar";; */emar) toolname="emar";; emar) toolname="emar";; */cosmoar) toolname="cosmoar";; cosmoar) toolname="cosmoar";; cc) toolname="gcc";; */cc) toolname="gcc";; c++) toolname="gxx";; */c++) toolname="gxx";; *) raise "unknown tool ${1}";; esac _ret="${toolname}" } # get flag name from toolkind, e.g. cc => cflags, cxx => cxxflags _get_flagname() { local toolkind="${1}" local flagname="" case "${toolkind}" in cc) flagname="cflags";; cxx) flagname="cxxflags";; as) flagname="asflags";; mm) flagname="mflags";; mxx) flagname="mxxflags";; ar) flagname="arflags";; sh) flagname="shflags";; ld) flagname="ldflags";; *) raise "unknown toolkind(${toolkind})!" ;; esac _ret="${flagname}" } # is enabled? true, yes, y _is_enabled() { local value=${1} if test_eq "${value}" "true"; then return 0 elif test_eq "${value}" "yes"; then return 0 elif test_eq "${value}" "y"; then return 0 fi return 1 } # deduplicate string list # .e.g "hello world hello how are you world" -> hello world how are you _dedup() { _ret=$(echo "${1}" | awk '{for (i = 1; i <= NF; ++i) if (!seen[$i]++) printf $i " "}') } # deduplicate string list from the reverse order # .e.g "hello world hello how are you world" -> hello how are you world _dedup_reverse() { local result="" local list="" local item="" list=$(echo "${1}" | awk '{for (i = NF; i > 0; --i) if (!seen[$i]++) printf $i " "}') for item in ${list}; do result="${item} ${result}" done _ret="${result}" } #----------------------------------------------------------------------------- # map functions # # define map, @note we can not use bash/declare to define map, because sh does not support it. # # _map "options" # _map_set "options" "key1" "value1" # _map_set "options" "key2" "value2" # _map_set "options" "key2" "value3" # _map_set "options" "key3" "value3" # _map_set "options" "key4" "__empty__" # _map_set "options" "key4" "__empty__" # _map_count "options"; _count="${_ret}" # _map_keys "options"; _keys="${_ret}" # echo ${_count} # for key in ${_keys}; do # _map_get "options" ${key}; value="{_ret}" # echo ${key} "->" ${value} # done # # echo "------" # _map_remove "options" "key3" # _map_count "options"; _count="${_ret}" # _map_keys "options"; _keys="${_ret}" # echo ${_count} # for key in ${_keys}; do # _map_get "options" ${key}; value="{_ret}" # echo ${key} "->" ${value} # done # _map() { local name=${1} # eval _map_${name}_count=0 # eval _map_${name}_keys="" } # because the shell is slow, we have to temporarily # disable some of the map features for performance. # #_map_count() { # local name=${1} # local count=$(eval echo \$_map_${name}_count) # _ret="${count}" #} _map_get() { local name="${1}" local key="${2}" _ret=$(eval echo \$_map_${name}_value_${key}) if test_eq "${_ret}" "__empty__"; then _ret="" fi } _map_has() { local name="${1}" local key="${2}" local value="" value=$(eval echo \$_map_${name}_value_${key}) if test_nz "${value}"; then return 0 fi return 1 } _map_set() { local name="${1}" local key="${2}" local value="${3}" # if ! _map_has ${name} ${key}; then # _map_count "options"; local count="${_ret}" # eval _map_${name}_count=$((${count} + 1)) # local keys=$(eval echo \$_map_${name}_keys) # keys="${keys} ${key}" # eval _map_${name}_keys=\${keys} # fi eval _map_${name}_value_${key}=\${value} } #_map_remove() { # local name="${1}" # local key="${2}" # if _map_has ${name} ${key}; then # _map_count "options"; local count="${_ret}" # eval _map_${name}_count=$((${count} - 1)) # eval _map_${name}_value_${key}="" # local keys=$(eval echo \$_map_${name}_keys) # local keys_new="" # local k="" # for k in ${keys}; do # if test_nq "${k}" "${key}"; then # keys_new="${keys_new} ${k}" # fi # done # eval _map_${name}_keys=\${keys_new} # fi #} #_map_keys() { # local name="${1}" # local keys=$(eval echo \$_map_${name}_keys) # _ret="${keys}" #} #----------------------------------------------------------------------------- # detect default environments # # detect hosts os_host=`uname` string_tolower ${os_host}; os_host="${_ret}" if echo "${os_host}" | grep cygwin >/dev/null 2>&1; then os_host="cygwin" fi if echo "${os_host}" | grep msys >/dev/null 2>&1; then os_host="msys" fi if echo "${os_host}" | grep mingw >/dev/null 2>&1; then os_host="msys" fi if echo "${os_host}" | grep darwin >/dev/null 2>&1; then os_host="macosx" fi if echo "${os_host}" | grep linux >/dev/null 2>&1; then os_host="linux" fi if echo "${os_host}" | grep freebsd >/dev/null 2>&1; then os_host="freebsd" fi if echo "${os_host}" | grep bsd >/dev/null 2>&1; then os_host="bsd" fi if echo "${os_host}" | grep Haiku >/dev/null 2>&1; then os_host="haiku" fi # determining host # e.g. # if is_host "linux" "macosx"; then # ... # fi is_host() { local host="" for host in $@; do if test_eq "${os_host}" "${host}"; then return 0 fi done return 1 } # detect host architecture os_arch=`uname -m | tr '[A-Z]' '[a-z]'` if test_eq "${os_arch}" "i686"; then os_arch="i386" elif test_eq "${os_arch}" "aarch64" || test_eq "${os_arch}" "arm64"; then os_arch="arm64" elif string_contains "${os_arch}" "armv7"; then os_arch="armv7" elif string_contains "${os_arch}" "arm"; then os_arch="arm" elif string_contains "${os_arch}" "power macintosh"; then os_arch="ppc" fi # set the default target platform _target_plat_default=${os_host} if is_host "msys"; then _target_plat_default="mingw" elif is_host "freebsd"; then _target_plat_default="bsd" elif test_nz "${EMSDK}"; then _target_plat_default="wasm" fi # set the default target architecture _target_arch_default=${os_arch} if is_host "msys" && test_nz "${MSYSTEM_CARCH}"; then _target_arch_default="${MSYSTEM_CARCH}" elif test_nz "${TERMUX_ARCH}"; then _target_arch_default="${TERMUX_ARCH}" elif test_nz "${EMSDK}"; then _target_arch_default="wasm32" fi if test_eq "${_target_arch_default}" "i686"; then _target_arch_default="i386" elif test_eq "${_target_arch_default}" "aarch64" || test_eq "${_target_arch_default}" "arm64"; then _target_arch_default="arm64" elif string_contains "${_target_arch_default}" "armv7"; then _target_arch_default="armv7" elif string_contains "${_target_arch_default}" "arm"; then _target_arch_default="arm" fi # set the default target mode _target_mode_default="release" # set the default target kind _target_kind_default="static" # set the default project generator and build program if is_host "freebsd" "bsd"; then project_generator="gmake" _make_program_default="gmake" _ninja_program_default="ninja" elif is_host "msys" "cygwin"; then project_generator="gmake" _make_program_default="make.exe" _ninja_program_default="ninja.exe" else project_generator="gmake" _make_program_default="make" _ninja_program_default="ninja" fi # set the default directories if test -d "/usr/local"; then _install_prefix_default="/usr/local" elif test -d "/usr"; then _install_prefix_default="/usr" fi _install_bindir_default="\${prefix}/bin" _install_libdir_default="\${prefix}/lib" _install_includedir_default="\${prefix}/include" # determining target platform # e.g. # if is_plat "linux" "macosx"; then # ... # fi is_plat() { local plat="" for plat in $@; do if test_eq "${_target_plat}" "${plat}"; then return 0 fi done return 1 } # determining target architecture # e.g. # if is_arch "x86_64" "i386"; then # ... # fi is_arch() { local arch="" for arch in $@; do if test_eq "${_target_arch}" "${arch}"; then return 0 fi done return 1 } # determining target mode # e.g. # if is_mode "release"; then # ... # fi is_mode() { local mode="" for mode in $@; do if test_eq "${_target_mode}" "${mode}"; then return 0 fi done return 1 } # determining target kind # e.g. # if is_kind "release"; then # ... # fi is_kind() { local kind="" for kind in $@; do if test_eq "${_target_kind}" "${kind}"; then return 0 fi done return 1 } # determining target toolchain # e.g. # if is_toolchain "clang"; then # ... # fi is_toolchain() { local toolchain="" for toolchain in $@; do if test_eq "${_target_toolchain}" "${toolchain}"; then return 0 fi done return 1 } #----------------------------------------------------------------------------- # project configuration apis # # set project name set_project() { _xmake_sh_project_name="${1}" } # include the given xmake.sh file or directory # e.g. includes "src" "tests" includes() { local path="" for path in $@; do if test -f "${path}"; then path_directory "${path}"; xmake_sh_scriptdir="${_ret}" . "${path}" else local xmake_sh_scriptdir_cur=${xmake_sh_scriptdir} if test "x${xmake_sh_scriptdir}" != "x"; then xmake_sh_scriptdir="${xmake_sh_scriptdir_cur}/${path}" . "${xmake_sh_scriptdir}/xmake.sh" else . "${xmake_sh_projectdir}/${path}/xmake.sh" fi xmake_sh_scriptdir=${xmake_sh_scriptdir_cur} fi done } #----------------------------------------------------------------------------- # some helper functions # # split flags _split_flags() { string_replace "${1}" ":" " " } # get abstract flag for gcc/clang _get_abstract_flag_for_gcc_clang() { local toolkind="${1}" local toolname="${2}" local itemname="${3}" local value="${4}" local flag="" case "${itemname}" in defines) string_replace "${value}" '"' '\\\"'; value="${_ret}" flag="-D${value}" ;; undefines) flag="-U${value}";; includedirs) flag="-I${value}";; linkdirs) flag="-L${value}";; links) flag="-l${value}";; syslinks) flag="-l${value}";; frameworks) flag="-framework ${value}";; frameworkdirs) flag="-F${value}";; rpathdirs) if is_plat "macosx"; then string_replace "${value}" "\$ORIGIN" "@loader_path"; value="${_ret}" flag="-Xlinker -rpath -Xlinker ${value}" else # escape $ORIGIN in makefile, TODO we need also handle it for ninja string_replace "${value}" "@loader_path" '$$ORIGIN'; value="${_ret}" if is_plat "bsd"; then flag="-Wl,-zorigin -Wl,-rpath='${value}'" else flag="-Wl,-rpath='${value}'" fi fi ;; symbols) if test_eq "${value}" "debug"; then flag="-g" elif test_eq "${value}" "hidden"; then flag="-fvisibility=hidden" fi ;; strip) if test_eq "${value}" "debug"; then flag="-Wl,-S" elif test_eq "${value}" "all"; then if is_plat "macosx"; then flag="-Wl,-x -Wl,-dead_strip" else flag="-s" fi fi ;; warnings) if test_eq "${value}" "all" || test_eq "${value}" "more" || test_eq "${value}" "less"; then flag="-Wall" elif test_eq "${value}" "allextra"; then flag="-Wall -Wextra" elif test_eq "${value}" "error"; then flag="-Werror" elif test_eq "${value}" "everything"; then flag="-Wall -Wextra" elif test_eq "${value}" "none"; then flag="-w" fi ;; optimizes) if test_eq "${value}" "fast"; then flag="-O1" elif test_eq "${value}" "faster"; then flag="-O2" elif test_eq "${value}" "fastest"; then flag="-O3" elif test_eq "${value}" "smallest"; then if test_eq "${toolname}" "clang" || test_eq "${toolname}" "clangxx"; then flag="-Oz" else flag="-Os" fi elif test_eq "${value}" "aggressive"; then flag="-Ofast" elif test_eq "${value}" "none"; then flag="-O0" fi ;; languages) if test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "mm"; then case "${value}" in ansi) flag="-ansi";; c89) flag="-std=c89";; gnu89) flag="-std=gnu89";; c99) flag="-std=c99";; gnu99) flag="-std=gnu99";; c11) flag="-std=c11";; gnu11) flag="-std=gnu11";; c17) flag="-std=c17";; gnu17) flag="-std=gnu17";; esac elif test_eq "${toolkind}" "cxx" || test_eq "${toolkind}" "mxx"; then case "${value}" in cxx98) flag="-std=c++98";; c++98) flag="-std=c++98";; gnuxx98) flag="-std=gnu++98";; gnu++98) flag="-std=gnu++98";; cxx11) flag="-std=c++11";; c++11) flag="-std=c++11";; gnuxx11) flag="-std=gnu++11";; gnu++11) flag="-std=gnu++11";; cxx14) flag="-std=c++14";; c++14) flag="-std=c++14";; gnuxx14) flag="-std=gnu++14";; gnu++14) flag="-std=gnu++14";; cxx17) flag="-std=c++17";; c++17) flag="-std=c++17";; gnuxx17) flag="-std=gnu++17";; gnu++17) flag="-std=gnu++17";; cxx1z) flag="-std=c++1z";; c++1z) flag="-std=c++1z";; gnuxx1z) flag="-std=gnu++1z";; gnu++1z) flag="-std=gnu++1z";; cxx2a) flag="-std=c++2a";; c++2a) flag="-std=c++2a";; gnuxx2a) flag="-std=gnu++2a";; gnu++2a) flag="-std=gnu++2a";; cxx20) flag="-std=c++20";; c++20) flag="-std=c++20";; gnuxx20) flag="-std=gnu++20";; gnu++20) flag="-std=gnu++20";; cxx*) raise "unknown language value(${value})!" ;; c++*) raise "unknown language value(${value})!" ;; esac fi ;; *) raise "unknown itemname(${itemname})!" ;; esac _ret="${flag}" } # get abstract flags _get_abstract_flags() { local toolkind="${1}" local toolname="${2}" local itemname="${3}" local values="${4}" local flags="" local value="" for value in ${values}; do local flag="" case "${toolname}" in gcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; gxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; clang) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; clangxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; emcc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; emxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; cosmocc) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; cosmocxx) _get_abstract_flag_for_gcc_clang "${toolkind}" "${toolname}" "${itemname}" "${value}"; flag="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac if test_nz "${flag}"; then flags="${flags} ${flag}" fi done _ret="${flags}" } #----------------------------------------------------------------------------- # option configuration apis # # define option option() { local name="${1}" local description="${2}" local default=${3} _xmake_sh_option_current="${name}" if ! ${_loading_options}; then if test_nz "${description}"; then _xmake_sh_option_current="" fi return fi if ! _map_has "options" "${name}_name"; then _xmake_sh_options="${_xmake_sh_options} ${name}" fi _map_set "options" "${name}_name" "${name}" _map_set "options" "${name}_description" "${description}" _map_set "options" "${name}_default" "${default}" # we end option if it's just one line if test_nz "${description}"; then _xmake_sh_option_current="" fi return 0 } option_end() { _xmake_sh_option_current="" } _map "options" # has the given option? _has_option() { local name=${1} if _map_has "options" "${name}_name"; then return 0 fi return 1 } # get the given option item _get_option_item() { local name=${1} local key=${2} _map_get "options" "${name}_${key}" } # set the given option item _set_option_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_set "options" "${name}_${key}" "${@}" else raise "please call set_${key}(${@}) in the option scope!" fi } # add values to the given option item _add_option_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_get "options" "${name}_${key}"; local values="${_ret}" values="${values} ${@}" _map_set "options" "${name}_${key}" "${values}" else raise "please call add_${key}(${@}) in the option scope!" fi } # get the give option value _get_option_value() { local name=${1} _get_option_item "${name}" "value" if test "x${_ret}" = "x"; then _get_option_item "${name}" "default" fi } # set the give option value _set_option_value() { local name=${1} local value=${2} _set_option_item "${name}" "value" "${value}" } # this option need checking? _option_need_checking() { local name="${1}" _get_option_item "${name}" "default"; local default="${_ret}" if test_nz "${default}"; then return 1 fi _get_option_item "${name}" "cfuncs"; local cfuncs="${_ret}" _get_option_item "${name}" "cxxfuncs"; local cxxfuncs="${_ret}" _get_option_item "${name}" "cincludes"; local cincludes="${_ret}" _get_option_item "${name}" "cxxincludes"; local cxxincludes="${_ret}" _get_option_item "${name}" "ctypes"; local ctypes="${_ret}" _get_option_item "${name}" "cxxtypes"; local cxxtypes="${_ret}" _get_option_item "${name}" "csnippets"; local csnippets="${_ret}" _get_option_item "${name}" "cxxsnippets"; local cxxsnippets="${_ret}" _get_option_item "${name}" "links"; local links="${_ret}" _get_option_item "${name}" "syslinks"; local syslinks="${_ret}" if test_nz "${cfuncs}" || test_nz "${cxxfuncs}" || test_nz "${cincludes}" || test_nz "${cxxincludes}" || test_nz "${ctypes}" || test_nz "${cxxtypes}" || test_nz "${csnippets}" || test_nz "${cxxsnippets}" || test_nz "${links}" || test_nz "${syslinks}"; then return 0 fi return 1 } # get options for the help menu _get_options_for_menu() { local options="" local name="" for name in ${_xmake_sh_options}; do _get_option_item "${name}" "showmenu"; local showmenu="${_ret}" if _is_enabled "${showmenu}"; then options="${options} ${name}" elif test_z "${showmenu}" && ! _option_need_checking "${name}"; then options="${options} ${name}" fi done _ret="${options}" } # get options for checking _get_options_for_checking() { local options="" local name="" for name in ${_xmake_sh_options}; do _get_option_item "${name}" "showmenu"; local showmenu="${_ret}" if test_z "${showmenu}" && _option_need_checking "${name}"; then options="${options} ${name}" fi done _ret="${options}" } # get abstract flags in option _get_option_abstract_flags() { local name="${1}" local toolkind="${2}" local toolname="${3}" local itemname="${4}" local values="${5}" if test_z "${values}"; then _get_option_item "${name}" "${itemname}"; values="${_ret}" fi _get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}" } # is config for option is_config() { if ! ${_loading_targets}; then return 1 fi local name=${1} local value=${2} _get_option_value "${name}"; local value_cur="${_ret}" if test_eq "${value_cur}" "${value}"; then return 0 fi return 1 } # has config for option has_config() { if ! ${_loading_targets}; then return 1 fi local name=${1} _get_option_value "${name}"; local value_cur="${_ret}" if _is_enabled ${value_cur}; then return 0 fi return 1 } # set config for option, we can use it to modify option status when loading targets set_config() { local name=${1} local value=${2} _set_option_value "${name}" "${value}" } # set showmenu in option set_showmenu() { if ! ${_loading_options}; then return fi local show="${1}" _set_option_item "${_xmake_sh_option_current}" "showmenu" "${show}" } # set description in option set_description() { if ! ${_loading_options}; then return fi local description="${1}" _set_option_item "${_xmake_sh_option_current}" "description" "${description}" } # add cfuncs in option add_cfuncs() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cfuncs" "${@}" } # add cxxfuncs in option add_cxxfuncs() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cxxfuncs" "${@}" } # add cincludes in option add_cincludes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cincludes" "${@}" } # add cxxincludes in option add_cxxincludes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cxxincludes" "${@}" } # add ctypes in option add_ctypes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "ctypes" "${@}" } # add cxxtypes in option add_cxxtypes() { if ! ${_loading_options}; then return fi _add_option_item "${_xmake_sh_option_current}" "cxxtypes" "${@}" } # add csnippets in option add_csnippets() { if ! ${_loading_options}; then return fi local csnippets="${1}" _add_option_item "${_xmake_sh_option_current}" "csnippets" "${csnippets}" } # add cxxsnippets in option add_cxxsnippets() { if ! ${_loading_options}; then return fi local cxxsnippets="${1}" _add_option_item "${_xmake_sh_option_current}" "cxxsnippets" "${cxxsnippets}" } # before_check in option before_check() { if ! ${_loading_options}; then return fi local funcname="${1}" _add_option_item "${_xmake_sh_option_current}" "before_check" "${funcname}" } #----------------------------------------------------------------------------- # target configuration apis # # define target target() { local name="${1}" _xmake_sh_target_current="${name}" if ! ${_loading_targets}; then return fi if ! _map_has "targets" "${name}_name"; then _xmake_sh_targets="${_xmake_sh_targets} ${name}" fi _map_set "targets" "${name}_name" "${name}" return 0 } target_end() { _xmake_sh_target_current="" } _map "targets" # has the given target? _has_target() { local name=${1} if _map_has "targets" "${name}_name"; then return 0 fi return 1 } # has the given target item _has_target_item() { local name=${1} local key=${2} if _map_has "targets" "${name}_${key}"; then return 0 elif _map_has "targets" "__root_${key}"; then return 0 fi return 1 } # get the given target item _get_target_item() { local name=${1} local key=${2} _map_get "targets" "${name}_${key}" local values="${_ret}" if _map_has "targets" "__root_${key}"; then _map_get "targets" "__root_${key}"; local root_values="${_ret}" if test_nz "${values}"; then values="${root_values} ${values}" else values="${root_values}" fi fi _ret="${values}" } # set the given target item _set_target_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_set "targets" "${name}_${key}" "${@}" else _map_set "targets" "__root_${key}" "${@}" fi } # add values to the given target item _add_target_item() { local name=${1} local key=${2} shift shift if test_nz "${name}"; then _map_get "targets" "${name}_${key}"; local values="${_ret}" values="${values} ${@}" _map_set "targets" "${name}_${key}" "${values}" else _map_get "targets" "__root_${key}"; local values="${_ret}" values="${values} ${@}" _map_set "targets" "__root_${key}" "${values}" fi } # is default? _is_target_default() { local name="${1}" if _has_target_item "${name}" "default"; then _get_target_item "${target}" "default"; local default="${_ret}" if _is_enabled ${default}; then return 0 fi return 1 fi return 0 } # get target basename _get_target_basename() { local name="${1}" _get_target_item "${name}" "basename"; local basename="${_ret}" if test_z "${basename}"; then basename="${name}" fi _ret="${basename}" } # get target extension _get_target_extension() { local name="${1}" local extension="" if _has_target_item "${name}" "extension"; then _get_target_item "${name}" "extension"; extension="${_ret}" elif is_plat "mingw"; then _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xbinary"; then extension=".exe" elif test "x${kind}" = "xstatic"; then extension=".a" elif test "x${kind}" = "xshared"; then extension=".dll" fi else _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xstatic"; then extension=".a" elif test "x${kind}" = "xshared"; then if is_plat "macosx"; then extension=".dylib" else extension=".so" fi fi fi _ret="${extension}" } # get target prefixname _get_target_prefixname() { local name="${1}" local prefixname="" if _has_target_item "${name}" "prefixname"; then _get_target_item "${name}" "prefixname"; prefixname="${_ret}" elif is_plat "mingw"; then _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xstatic"; then prefixname="lib" elif test "x${kind}" = "xshared"; then prefixname="lib" fi else _get_target_item "${name}" "kind"; local kind="${_ret}" if test "x${kind}" = "xstatic"; then prefixname="lib" elif test "x${kind}" = "xshared"; then prefixname="lib" fi fi _ret="${prefixname}" } # get target filename _get_target_filename() { local name="${1}" _get_target_item "${name}" "filename"; local filename="${_ret}" if test_z "${filename}"; then _get_target_basename "${name}"; local basename="${_ret}" _get_target_extension "${name}"; local extension="${_ret}" _get_target_prefixname "${name}"; local prefixname="${_ret}" filename="${prefixname}${basename}${extension}" fi _ret="${filename}" } # get target soname # @see https://github.com/tboox/tbox/issues/214 # # set_version "1.0.1" "" "1" -> libfoo.so.1, libfoo.1.dylib # set_version "1.0.1" "" "A" -> libfoo.so.A, libfoo.A.dylib _get_target_soname() { local soname="" local name="${1}" _get_target_item "${name}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared" && is_plat "macosx" "linux" "bsd"; then _get_target_item "${name}" "version"; local version="${_ret}" _get_target_item "${name}" "version_soname"; local version_soname="${_ret}" if test_nz "${version}" && test_nz "${version_soname}"; then _get_target_filename "${name}"; soname="${_ret}" _get_target_extension "${name}"; local extension="${_ret}" if test_eq "${extension}" ".dylib"; then path_basename "${soname}"; local basename="${_ret}" soname="${basename}.${version_soname}${extension}" else soname="${soname}.${version_soname}" fi fi fi _ret="${soname}" } # get target directory _get_targetdir() { local name="${1}" _get_target_item "${name}" "targetdir"; local targetdir="${_ret}" if test_z "${targetdir}"; then targetdir="${xmake_sh_buildir}/${_target_plat}/${_target_arch}/${_target_mode}" fi _ret="${targetdir}" } # get target object directory _get_target_objectdir() { local name="${1}" _get_target_item "${name}" "objectdir"; local objectdir="${_ret}" if test_z "${objectdir}"; then objectdir="${xmake_sh_buildir}/.objs/${name}/${_target_plat}/${_target_arch}/${_target_mode}" fi _ret="${objectdir}" } # get target file path _get_target_file() { local name="${1}" _get_target_filename "${name}"; local filename="${_ret}" _get_targetdir "${name}"; local targetdir="${_ret}" local targetfile="${targetdir}/${filename}" _ret="${targetfile}" } # get target librarydeps _get_target_librarydeps_impl() { local name="${1}" local librarydeps="" local dep="" _get_target_item "${name}" "deps"; local deps="${_ret}" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then librarydeps="${librarydeps} ${dep}" _get_target_librarydeps_impl "${dep}"; local dep_librarydeps="${_ret}" if test_nz "${dep_librarydeps}"; then librarydeps="${librarydeps} ${dep_librarydeps}" fi fi done _ret="${librarydeps}" } _get_target_librarydeps() { local name="${1}" _get_target_item "${name}" "librarydeps"; local librarydeps="${_ret}" if test_z "${librarydeps}" && test_nq "${librarydeps}" "__none__"; then _get_target_librarydeps_impl "${name}"; librarydeps="${_ret}" if test_nz "${librarydeps}"; then _dedup_reverse "${librarydeps}"; librarydeps="${_ret}" _set_target_item "${name}" "librarydeps" "${librarydeps}" else _set_target_item "${name}" "librarydeps" "__none__" fi fi if test_eq "${librarydeps}" "__none__"; then librarydeps="" fi _ret="${librarydeps}" } # get sourcefiles in target _get_target_sourcefiles() { local name="${1}" _get_target_item "${name}" "files" } # get objectfile in target _get_target_objectfile() { local name="${1}" local sourcefile="${2}" local extension=".o" if is_plat "mingw"; then extension=".obj" fi _get_target_objectdir "${name}"; local objectdir="${_ret}" local objectfile="${objectdir}/${sourcefile}${extension}" _ret="${objectfile}" } # get objectfiles in target _get_target_objectfiles() { local name="${1}" _get_target_sourcefiles "${name}"; local sourcefiles="${_ret}" local objectfiles="" local sourcefile="" for sourcefile in ${sourcefiles}; do _get_target_objectfile "${name}" "${sourcefile}"; local objectfile="${_ret}" objectfiles="${objectfiles} ${objectfile}" done _ret="${objectfiles}" } # get abstract flags in target _get_target_abstract_flags() { local name="${1}" local toolkind="${2}" local toolname="${3}" local itemname="${4}" local values="${5}" if test_z "${values}"; then # get values from target _get_target_item "${name}" "${itemname}"; values="${_ret}" # get values from target deps _get_target_librarydeps "${name}"; local deps="${_ret}" local dep="" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_target_item "${dep}" "${itemname}_public"; local depvalues="${_ret}" if test_nz "${depvalues}"; then values="${values} ${depvalues}" fi fi done fi if test_nz "${values}"; then _get_abstract_flags "${toolkind}" "${toolname}" "${itemname}" "${values}" else _ret="" fi } # get toolchain flags for ar in target _get_target_toolchain_flags_for_ar() { _ret="-cr" } # get toolchain flags for gcc in target _get_target_toolchain_flags_for_gcc() { local name="${1}" local toolkind="${2}" local flags="" if is_arch "i386"; then flags="${flags} -m32" fi _get_target_item "${name}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then if test_eq "${toolkind}" "sh"; then flags="${flags} -shared -fPIC" elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then flags="${flags} -fPIC" fi # @see https://github.com/tboox/tbox/issues/214 if test_eq "${toolkind}" "sh"; then _get_target_soname "${name}"; local soname="${_ret}" if test_nz "${soname}"; then if is_plat "macosx"; then flags="${flags} -Wl,-install_name,${soname}" else flags="${flags} -Wl,-soname,${soname}" fi fi fi fi _ret="${flags}" } # get toolchain flags for clang in target _get_target_toolchain_flags_for_clang() { local name="${1}" local toolkind="${2}" local flags="-Qunused-arguments" if is_arch "i386"; then flags="${flags} -m32" fi _get_target_item "${name}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then if test_eq "${toolkind}" "sh"; then flags="${flags} -shared -fPIC" elif test_eq "${toolkind}" "cc" || test_eq "${toolkind}" "cxx"; then flags="${flags} -fPIC" fi # @see https://github.com/tboox/tbox/issues/214 if test_eq "${toolkind}" "sh"; then _get_target_soname "${name}"; local soname="${_ret}" if test_nz "${soname}"; then if is_plat "macosx"; then flags="${flags} -Wl,-install_name,${soname}" else flags="${flags} -Wl,-soname,${soname}" fi fi fi fi if is_plat "macosx"; then _os_iorunv "xcrun" "-sdk" "macosx" "--show-sdk-path"; local sdkdir="${_ret}" if test_nz "${sdkdir}"; then flags="${flags} -isysroot \"${sdkdir}\"" fi fi _ret="${flags}" } # get toolchain flags in target _get_target_toolchain_flags() { local name="${1}" local toolkind="${2}" local toolname="${3}" local flags="" case "${toolname}" in gcc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; gxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; clang) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; clangxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; emcc) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; emxx) _get_target_toolchain_flags_for_clang "${name}" "${toolkind}"; flags="${_ret}";; cosmocc) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; cosmocxx) _get_target_toolchain_flags_for_gcc "${name}" "${toolkind}"; flags="${_ret}";; ar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";; emar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";; cosmoar) _get_target_toolchain_flags_for_ar "${name}" "${toolkind}"; flags="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac _ret="${flags}" } # get compiler flags in target _get_target_compiler_flags() { local name="${1}" local toolkind="${2}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local result="" # get toolchain flags _get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}" if test_nz "${toolchain_flags}"; then result="${result} ${toolchain_flags}" fi # get abstract flags local itemnames="symbols optimizes warnings languages defines undefines includedirs frameworkdirs frameworks" local itemname="" for itemname in ${itemnames}; do _get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi done # get raw flags, e.g. add_cflags, add_cxxflags _get_flagname "${toolkind}"; local flagname="${_ret}" _get_target_item "${name}" "${flagname}"; local flags="${_ret}" # get flags from target deps _get_target_librarydeps "${name}"; local deps="${_ret}" local dep="" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}" if test_nz "${depflags}"; then flags="${flags} ${depflags}" fi fi done if test_nz "${flags}"; then result="${result} ${flags}" fi if test_eq "${flagname}" "cflags" || test_eq "${flagname}" "cxxflags"; then _get_target_item "${name}" "cxflags"; flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi elif test_eq "${flagname}" "mflags" || test_eq "${flagname}" "mxxflags"; then _get_target_item "${name}" "mxflags"; flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi fi # get flags from environments, e.g. $CFLAGS, $CXXFLAGS if test_nz "${CPPFLAGS}"; then result="${result} ${CPPFLAGS}" fi if test_eq "${flagname}" "cflags" && test_nz "${CFLAGS}"; then result="${result} ${CFLAGS}" fi if test_eq "${flagname}" "cxxflags" && test_nz "${CXXFLAGS}"; then result="${result} ${CXXFLAGS}" fi if test_eq "${flagname}" "mflags" && test_nz "${MFLAGS}"; then result="${result} ${MFLAGS}" fi if test_eq "${flagname}" "mxxflags" && test_nz "${MXXFLAGS}"; then result="${result} ${MXXFLAGS}" fi _ret="${result}" } # get linker flags in target _get_target_linker_flags() { local name="${1}" local toolkind="${2}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local result="" # get toolchain flags _get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}" if test_nz "${toolchain_flags}"; then result="${result} ${toolchain_flags}" fi # get flags from target deps _get_target_librarydeps "${name}"; local deps="${_ret}" local dep="" for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_targetdir "${dep}"; local dep_targetdir="${_ret}" _get_target_basename "${dep}"; local dep_basename="${_ret}" _get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "linkdirs" "${dep_targetdir}"; local linkdirs_flags="${_ret}" _get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "links" "${dep_basename}"; local links_flags="${_ret}" if test_eq "${dep_kind}" "shared"; then local rpathdir="@loader_path" _get_targetdir "${name}"; local targetdir="${_ret}" path_relative "${targetdir}" "${dep_targetdir}"; local subdir="${_ret}" if test_nz "${subdir}"; then rpathdir="${rpathdir}/${subdir}" fi _get_target_abstract_flags "${dep}" "${toolkind}" "${toolname}" "rpathdirs" "${rpathdir}"; local rpathdirs_flags="${_ret}" result="${result} ${rpathdirs_flags}" fi result="${result} ${linkdirs_flags} ${links_flags}" fi done # get abstract flags local itemnames="strip frameworkdirs linkdirs links rpathdirs frameworks syslinks" local itemname="" for itemname in ${itemnames}; do _get_target_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi done # get raw flags, e.g. add_ldflags, add_shflags _get_flagname "${toolkind}"; local flagname="${_ret}" _get_target_item "${name}" "${flagname}"; local flags="${_ret}" # get flags from target deps for dep in ${deps}; do _get_target_item "${dep}" "kind"; local dep_kind="${_ret}" if test_eq "${dep_kind}" "static" || test_eq "${dep_kind}" "shared"; then _get_target_item "${dep}" "${flagname}_public"; local depflags="${_ret}" if test_nz "${depflags}"; then flags="${flags} ${depflags}" fi fi done if test_nz "${flags}"; then result="${result} ${flags}" fi # get flags from environments, e.g. $LDFLAGS if test_eq "${flagname}" "ldflags" && test_nz "${LDFLAGS}"; then result="${result} ${LDFLAGS}" fi if test_eq "${flagname}" "shflags" && test_nz "${LDFLAGS}"; then result="${result} ${LDFLAGS}" fi _ret="${result}" } # get archiver flags in target _get_target_archiver_flags() { local name="${1}" local toolkind="${2}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local result="" # get toolchain flags _get_target_toolchain_flags "${name}" "${toolkind}" "${toolname}"; local toolchain_flags="${_ret}" if test_nz "${toolchain_flags}"; then result="${result} ${toolchain_flags}" fi # get raw flags, e.g. add_arflags _get_flagname "${toolkind}"; local flagname="${_ret}" _get_target_item "${name}" "${flagname}"; local flags="${_ret}" if test_nz "${flags}"; then result="${result} ${flags}" fi _ret="${result}" } # get target flags _get_target_flags() { local name="${1}" local toolkind="${2}" local flags="" if test_eq "${toolkind}" "sh"; then _get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}" elif test_eq "${toolkind}" "ld"; then _get_target_linker_flags "${name}" "${toolkind}"; flags="${_ret}" elif test_eq "${toolkind}" "ar"; then _get_target_archiver_flags "${name}" "${toolkind}"; flags="${_ret}" else _get_target_compiler_flags "${name}" "${toolkind}"; flags="${_ret}" fi _ret="${flags}" } # add file paths in target _add_target_filepaths() { local key="$1" shift # we need avoid escape `*` automatically in for-loop local file="" string_replace "${@}" "\*" "?"; local list="${_ret}" if test_eq "${key}" "files"; then for file in ${list}; do path_sourcekind "${file}"; local sourcekind="${_ret}" _targets_toolkinds="${_targets_toolkinds} ${sourcekind}" done fi for file in ${list}; do string_replace "${file}" "?" "*"; file="${_ret}" if ! path_is_absolute "${file}"; then file="${xmake_sh_scriptdir}/${file}" fi local files="" if string_contains_star2 "${file}"; then path_directory "${file}"; local dir="${_ret}" path_filename_fromdir "${file}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}"; files="${_ret}" elif string_contains_star "${file}"; then path_directory "${file}"; local dir="${_ret}" path_filename_fromdir "${file}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}" 1; files="${_ret}" else files="${file}" fi for file in ${files}; do path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}" _add_target_item "${_xmake_sh_target_current}" "${key}" "${file}" done done } # add install paths in target _add_target_installpaths() { local key="$1" local filepattern="${2}" local prefixdir="${3}" local filename=${4} # get root directory, e.g. "src/foo/(*.h)" -> "src/foo" local rootdir="" if string_contains "${filepattern}" "("; then string_split "${filepattern}" "(" 1; rootdir="${_ret}" rootdir=${rootdir%/} if ! path_is_absolute "${rootdir}"; then rootdir="${xmake_sh_scriptdir}/${rootdir}" fi path_relative "${xmake_sh_projectdir}" "${rootdir}"; rootdir="${_ret}" rootdir=${rootdir%/} fi # remove (), e.g. "src/(*.h)" -> "src/*.h" string_replace ${filepattern} "(" ""; filepattern="${_ret}" string_replace ${filepattern} ")" ""; filepattern="${_ret}" # get real path if ! path_is_absolute "${filepattern}"; then filepattern="${xmake_sh_scriptdir}/${filepattern}" fi local files="" if string_contains_star2 "${filepattern}"; then path_directory "${filepattern}"; local dir="${_ret}" path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}"; files="${_ret}" elif string_contains_star "${filepattern}"; then path_directory "${filepattern}"; local dir="${_ret}" path_filename_fromdir "${filepattern}" "${dir}"; local name="${_ret}" _os_find "${dir}" "${name}" 1; files="${_ret}" else files="${filepattern}" fi for file in ${files}; do path_relative "${xmake_sh_projectdir}" "${file}"; file="${_ret}" _add_target_item "${_xmake_sh_target_current}" "${key}" "${file}:${rootdir}:${prefixdir}:${filename}" done } # set target file path _set_target_filepath() { local key="${1}" local path="${2}" if ! path_is_absolute "${path}"; then path="${xmake_sh_scriptdir}/${path}" fi path_relative ${xmake_sh_projectdir} "${path}"; path="${_ret}" _set_target_item "${_xmake_sh_target_current}" "${key}" "${path}" } # set kind in target set_kind() { if ! ${_loading_targets}; then return fi local kind=${1} _set_target_item "${_xmake_sh_target_current}" "kind" "${kind}" case "${kind}" in binary) _targets_toolkinds="${_targets_toolkinds} ld";; static) _targets_toolkinds="${_targets_toolkinds} ar";; shared) _targets_toolkinds="${_targets_toolkinds} sh";; *) raise "unknown target kind ${kind}";; esac } # set version in target set_version() { if ! ${_loading_targets}; then return fi local version="${1}" local version_build="${2}" local version_soname="${3}" _set_target_item "${_xmake_sh_target_current}" "version" "${version}" _set_target_item "${_xmake_sh_target_current}" "version_build" "${version_build}" _set_target_item "${_xmake_sh_target_current}" "version_soname" "${version_soname}" } # set default in target set_default() { local default=${1} if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "default" "${default}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "default" "${default}" fi } # set configvar in target set_configvar() { if ! ${_loading_targets}; then return fi local name="${1}" local value="${2}" _set_target_item "${_xmake_sh_target_current}" "configvar_${name}" "${value}" _add_target_item "${_xmake_sh_target_current}" "configvars" "${name}" } # set filename in target set_filename() { if ! ${_loading_targets}; then return fi local filename="${1}" _set_target_item "${_xmake_sh_target_current}" "filename" "${filename}" } # set basename in target set_basename() { if ! ${_loading_targets}; then return fi local basename="${1}" _set_target_item "${_xmake_sh_target_current}" "basename" "${basename}" } # set extension in target set_extension() { if ! ${_loading_targets}; then return fi local extension=${1} _set_target_item "${_xmake_sh_target_current}" "extension" "${extension}" } # set prefixname in target set_prefixname() { if ! ${_loading_targets}; then return fi local prefixname=${1} _set_target_item "${_xmake_sh_target_current}" "prefixname" "${prefixname}" } # set target directory set_targetdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "targetdir" "${1}" } # set target object directory set_objectdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "objectdir" "${1}" } # set target config directory set_configdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "configdir" "${1}" } # set target install directory set_installdir() { if ! ${_loading_targets}; then return fi _set_target_filepath "installdir" "${1}" } # add deps in target add_deps() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "deps" "${@}" } # add files in target add_files() { if ! ${_loading_targets}; then return fi _add_target_filepaths "files" "$@" } # add install files in target add_installfiles() { if ! ${_loading_targets}; then return fi _add_target_installpaths "installfiles" "$@" } # add header files in target add_headerfiles() { if ! ${_loading_targets}; then return fi _add_target_installpaths "headerfiles" "$@" } # add config files in target add_configfiles() { if ! ${_loading_targets}; then return fi _add_target_filepaths "configfiles" "$@" } # add defines in target add_defines() { local define="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for define in $@; do if test_nq "${define}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "defines" "${define}" else public=true fi done if ${public}; then for define in $@; do if test_nq "${define}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "defines_public" "${define}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "defines" "${@}" fi } # add undefines in target add_undefines() { local undefine="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for undefine in $@; do if test_nq "${undefine}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "undefines" "${undefine}" else public=true fi done if ${public}; then for undefine in $@; do if test_nq "${undefine}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "undefines_public" "${undefine}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "undefines" "${@}" fi } # add includedirs in target add_includedirs() { local public=false local dir="" for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "includedirs" "${dir}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "includedirs" "${dir}" fi else public=true fi done if ${public}; then for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "includedirs_public" "${dir}" fi fi done fi } # add links in target add_links() { local link="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for link in $@; do if test_nq "${link}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "links" "${link}" else public=true fi done if ${public}; then for link in $@; do if test_nq "${link}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "links_public" "${link}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "links" "${@}" fi } # add syslinks in target add_syslinks() { local syslink="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for syslink in $@; do if test_nq "${syslink}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "syslinks" "${syslink}" else public=true fi done if ${public}; then for syslink in $@; do if test_nq "${syslink}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "syslinks_public" "${syslink}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "syslinks" "${@}" fi } # add linkdirs in target add_linkdirs() { local dir="" local public=false for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "linkdirs" "${dir}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "linkdirs" "${dir}" fi else public=true fi done if ${public}; then for dir in $@; do if test_nq "${dir}" "{public}"; then if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi if string_startswith "${dir}" "${xmake_sh_projectdir}"; then path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" fi if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "linkdirs_public" "${dir}" fi fi done fi } # add rpathdirs in target add_rpathdirs() { if ! ${_loading_targets}; then return fi local dir="" for dir in $@; do if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" _add_target_item "${_xmake_sh_target_current}" "rpathdirs" "${dir}" done } # add frameworks in target add_frameworks() { local framework="" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then local public=false for framework in $@; do if test_nq "${framework}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "frameworks" "${framework}" else public=true fi done if ${public}; then for framework in $@; do if test_nq "${framework}" "{public}"; then _add_target_item "${_xmake_sh_target_current}" "frameworks_public" "${framework}" fi done fi elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "frameworks" "${@}" fi } # add frameworkdirs in target add_frameworkdirs() { local dir="" for dir in $@; do if ! path_is_absolute "${dir}"; then dir="${xmake_sh_scriptdir}/${dir}" fi path_relative ${xmake_sh_projectdir} "${dir}"; dir="${_ret}" if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "frameworkdirs" "${dir}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "frameworkdirs" "${dir}" fi done } # set strip in target set_strip() { if ! ${_loading_targets}; then return fi local strip=${1} _set_target_item "${_xmake_sh_target_current}" "strip" "${strip}" } # set symbols in target set_symbols() { if ! ${_loading_targets}; then return fi local symbols="${1}" _set_target_item "${_xmake_sh_target_current}" "symbols" "${symbols}" } # set languages in target set_languages() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "languages" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "languages" "${@}" fi } # set warnings in target set_warnings() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "warnings" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "warnings" "${@}" fi } # set optimizes in target set_optimizes() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _set_target_item "${_xmake_sh_target_current}" "optimizes" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _set_option_item "${_xmake_sh_option_current}" "optimizes" "${@}" fi } # add cflags in target add_cflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "cflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "cflags" "${@}" fi } # add cxflags in target add_cxflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "cxflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "cxflags" "${@}" fi } # add cxxflags in target add_cxxflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "cxxflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "cxxflags" "${@}" fi } # add asflags in target add_asflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "asflags" "${@}" } # add mflags in target add_mflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "mflags" "${@}" } # add mxflags in target add_mxflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "mxflags" "${@}" } # add mxxflags in target add_mxxflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "mxxflags" "${@}" } # add ldflags in target add_ldflags() { if ${_loading_targets} && test_z "${_xmake_sh_option_current}"; then _add_target_item "${_xmake_sh_target_current}" "ldflags" "${@}" elif ${_loading_options} && test_nz "${_xmake_sh_option_current}"; then _add_option_item "${_xmake_sh_option_current}" "ldflags" "${@}" fi } # add shflags in target add_shflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "shflags" "${@}" } # add arflags in target add_arflags() { if ! ${_loading_targets}; then return fi _add_target_item "${_xmake_sh_target_current}" "arflags" "${@}" } # add options in target add_options() { if ! ${_loading_targets}; then return fi local name="" local public=false for name in $@; do if test_nq "${name}" "{public}"; then public=true break fi done for name in $@; do if has_config "${name}"; then local itemname="" local itemnames="includedirs linkdirs links defines cflags cxflags cxxflags ldflags" for itemname in ${itemnames}; do _get_option_item "${name}" "${itemname}"; local values="${_ret}" if test_nz "${values}"; then _add_target_item "${_xmake_sh_target_current}" "${itemname}" "${values}" if $public; then _add_target_item "${_xmake_sh_target_current}" "${itemname}_public" "${values}" fi fi done fi done } # before_install in target before_install() { if ! ${_loading_targets}; then return fi local funcname="${1}" _add_target_item "${_xmake_sh_target_current}" "before_install" "${funcname}" } # after_install in target after_install() { if ! ${_loading_targets}; then return fi local funcname="${1}" _add_target_item "${_xmake_sh_target_current}" "after_install" "${funcname}" } #----------------------------------------------------------------------------- # toolchain configuration apis # # define toolchain toolchain() { local name="${1}" _xmake_sh_toolchain_current="${name}" if ! ${_loading_toolchains}; then return fi _xmake_sh_toolchains="${_xmake_sh_toolchains} ${name}" _map_set "toolchains" "${name}_name" "${name}" return 0 } toolchain_end() { _xmake_sh_toolchain_current="" } _map "toolchains" # has the given toolchain? _has_toolchain() { local name=${1} if _map_has "toolchains" "${name}_name"; then return 0 fi return 1 } # get the given toolchain item _get_toolchain_item() { local name=${1} local key=${2} _map_get "toolchains" "${name}_${key}" } # set the given toolchain item _set_toolchain_item() { local name=${1} local key=${2} local value=${3} if test_nz "${name}"; then _map_set "toolchains" "${name}_${key}" "${value}" else raise "please set toolchain in the toolchain scope!" fi } # get the give toolchain toolset _get_toolchain_toolset() { local name=${1} local kind=${2} _get_toolchain_item "${name}" "toolset_${kind}" } # set the give toolchain toolset _set_toolchain_toolset() { local name=${1} local kind=${2} local programs="${3}" _set_toolchain_item "${name}" "toolset_${kind}" "${programs}" } # add the give toolchain toolset _add_toolchain_toolset() { local name=${1} local kind=${2} local program="${3}" _get_toolchain_item "${name}" "toolset_${kind}"; local programs="${_ret}" if test_nz "${programs}"; then programs="${programs}:${program}" else programs="${program}" fi _set_toolchain_item "${name}" "toolset_${kind}" "${programs}" } # set toolset in toolchain set_toolset() { if ! ${_loading_toolchains}; then return fi local kind=${1} shift local idx=0 while test $# != 0; do local program="${1}" local key="${kind}" if test_nq "${idx}" "0"; then key="${key}_${idx}" fi _set_toolchain_toolset "${_xmake_sh_toolchain_current}" "${key}" "${program}" idx=$((idx+1)) shift done } #----------------------------------------------------------------------------- # load options # # load options and toolchains _load_options_and_toolchains() { _loading_options=true _loading_toolchains=true _loading_targets=false local file=${xmake_sh_projectdir}/xmake.sh if test -f "${file}"; then includes "${file}" else # include all xmake.sh files in next sub-directories local files=`find ${xmake_sh_projectdir} -maxdepth 2 -mindepth 2 -name "xmake.sh"` for file in ${files}; do includes "${file}" done fi } _load_options_and_toolchains # show option usage _show_options_usage() { _get_options_for_menu; local options="${_ret}" for name in ${options}; do _get_option_item "${name}" "description"; local description="${_ret}" _get_option_item "${name}" "default"; local default="${_ret}" string_toupper ${name}; local head="--${name}="${_ret}"" local headsize=${#head} local tail="${description}" if test "x${default}" != "x"; then local defval=${default} if test "x${defval}" = "xtrue"; then defval="yes" elif test "x${defval}" = "xfalse"; then defval="no" fi tail="${tail} (default: ${defval})" fi local width=24 local padding_width=$((${width} - ${headsize})) local padding=$(string_dupch ${padding_width} " ") echo " ${head}${padding}${tail}" done } # show configure usage _show_usage() { echo ' Usage: '"$0"' [...] Options: [defaults in brackets after descriptions] Common options: --help Print this message. --version Only print version information. --verbose Display more information. --diagnosis Display lots of diagnosis information. --generator=GENERATOR Set the project generator. (default: '"${project_generator}"') - gmake - ninja --make=MAKE Set the make program. (default: '"${_make_program_default}"') --ninja=NINJA Set the Ninja program. (default: '"${_ninja_program_default}"') --plat=PLAT Compile for the given platform. (default: '"${_target_plat_default}"') - msys - cross - bsd - mingw - macosx - linux - wasm --arch=ARCH Compile for the given architecture. (default: '"${_target_arch_default}"') - msys: i386 x86_64 - cross: i386 x86_64 arm arm64 mips mips64 riscv riscv64 loong64 s390x ppc ppc64 sh4 - bsd: i386 x86_64 - mingw: i386 x86_64 arm arm64 - macosx: x86_64 arm64 - linux: i386 x86_64 armv7 armv7s arm64-v8a mips mips64 mipsel mips64el --mode=MODE Set the given compilation mode. (default: '"${_target_mode_default}"') - release - debug --kind=KIND Set the given target kind. (default: '"${_target_kind_default}"') - static - shared - binary --toolchain=TOOLCHAIN Set toolchain name. - clang - gcc - emcc - cosmocc --buildir=DIR Set build directory. (default: '"${xmake_sh_buildir}"') Autoconf options: --build=BUILD Configure for building on BUILD [guessed] --host=HOST Cross-compile to build programs to run on HOST [BUILD] --prefix=PREFIX Set install files directory in tree rooted at PREFIX. (default: '"${_install_prefix_default}"') --bindir=DIR Set install binaries directory in PREFIX/DIR. (default: '"${_install_bindir_default}"') --libdir=DIR Set install libraries directory in PREFIX/DIR. (default: '"${_install_libdir_default}"') --includedir=DIR Set install includes directory in PREFIX/DIR. (default: '"${_install_includedir_default}"') Project options: '"$(_show_options_usage)"' ' exit 1 } # show xmake.sh version _show_version() { echo "xmake.sh v${xmake_sh_version}, A script-only build utility like autotools" echo "${xmake_sh_copyright}" echo ' _ _ ' echo " __ ___ __ __ __ _| | ______ ___| |__ " echo " \ \/ / | \/ |/ _ | |/ / __ \ / __| '_ \ " echo " > < | \__/ | /_| | < ___/_\__ \ | | | " echo " /_/\_\_|_| |_|\__ \|_|\_\____(_)___/_| |_| " echo ' by ruki, xmake.io' echo ' ' echo ' 👉 Manual: https://xmake.io/#/getting_started ' echo ' 🙏 Donate: https://xmake.io/#/sponsor ' echo ' ' exit 2 } # --foo=yes => foo _parse_argument_name() { _ret=$(echo "${1#*--}" | sed "s/${2-=[^=]*}$//") string_replace "${_ret}" "-" "_" } # --foo=yes => yes _parse_argument_value() { _ret=$(echo "$1" | sed "s/^${2-[^=]*=}//") } # parse input arguments _handle_option() { _parse_argument_name ${1}; local name="${_ret}" _parse_argument_value ${1}; local value="${_ret}" if test_eq "${name}" "help"; then _show_usage return 0 elif test_eq "${name}" "version"; then _show_version return 0 elif test_eq "${name}" "verbose"; then xmake_sh_verbose=true return 0 elif test_eq "${name}" "diagnosis"; then xmake_sh_diagnosis=true return 0 elif test_eq "${name}" "plat"; then _target_plat=${value} return 0 elif test_eq "${name}" "arch"; then _target_arch=${value} return 0 elif test_eq "${name}" "mode"; then _target_mode=${value} return 0 elif test_eq "${name}" "kind"; then _target_kind=${value} return 0 elif test_eq "${name}" "toolchain"; then _target_toolchain=${value} return 0 elif test_eq "${name}" "generator"; then project_generator=${value} return 0 elif test_eq "${name}" "make"; then _make_program=${value} return 0 elif test_eq "${name}" "ninja"; then _ninja_program=${value} return 0 elif test_eq "${name}" "prefix"; then _install_prefix_default="${value}" return 0 elif test_eq "${name}" "bindir"; then _install_bindir_default="${value}" return 0 elif test_eq "${name}" "libdir"; then _install_libdir_default="${value}" return 0 elif test_eq "${name}" "includedir"; then _install_includedir_default="${value}" return 0 elif test_eq "${name}" "buildir"; then xmake_sh_buildir="${value}" return 0 elif test_eq "${name}" "build"; then _autoconf_build_type="${value}" return 0 elif test_eq "${name}" "host"; then _autoconf_host_type="${value}" return 0 elif _has_option "${name}"; then _set_option_value "${name}" "${value}" return 0 fi return 1 } while test $# != 0; do if ! _handle_option ${1}; then wprint "unknown option: $1" fi shift done #----------------------------------------------------------------------------- # handle some autoconf configurations # # parse triplet # https://github.com/xmake-io/xmake/issues/3869 # e.g. i686-linux-gnu, aarch64-apple-darwin, x86_64-w64-mingw32, i686-redhat-linux-gnu _parse_triplet() { local triplet="${1}" string_split "${triplet}" "-" } _get_arch_from_cpu() { local cpu="${1}" case "${cpu}" in i686) _ret="i386";; i386) _ret="i386";; x86_64) _ret="x86_64";; aarch64) _ret="arm64";; arm64) _ret="arm64";; arm*) _ret="arm";; *) _ret="${cpu}";; esac } _get_plat_from_vendor_os() { local vendor="${1}" local os="${2}" case "${vendor}" in linux) if string_contains "${os}" "android"; then _ret="android" else _ret="linux" fi ;; apple) if test_eq "${os}" "darwin"; then _ret="macosx" fi ;; w64) _ret="mingw";; *) _ret="${os}";; esac } _handle_autoconf_configs() { if test_z "${_autoconf_host_type}"; then _autoconf_host_type="${_autoconf_build_type}" fi if test_nz "${_autoconf_build_type}"; then _parse_triplet "${_autoconf_build_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}" _get_arch_from_cpu "${cpu}" if test_nz "${_ret}"; then os_arch="${_ret}" else wprint "unknown cpu: ${cpu} in --build=${value}" fi _get_plat_from_vendor_os "${vendor}" "${os}" if test_nz "${_ret}"; then os_host="${_ret}" else wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}" fi fi if test_nz "${_autoconf_host_type}"; then _parse_triplet "${_autoconf_host_type}"; local cpu="${_ret}"; local vendor="${_ret2}"; local os="${_ret3}" _get_arch_from_cpu "${cpu}" if test_nz "${_ret}"; then _target_arch_default="${_ret}" else wprint "unknown cpu: ${cpu} in --host=${value}" fi _get_plat_from_vendor_os "${vendor}" "${os}" if test_nz "${_ret}"; then _target_plat_default="${_ret}" else wprint "unknown vendor-os: ${vendor}-${os} in --build=${value}" fi fi } _handle_autoconf_configs #----------------------------------------------------------------------------- # detect platform and toolchains # # envs toolchain toolchain "envs" set_toolset "as" "$CC" "$CXX" "$AS" set_toolset "cc" "$CC" set_toolset "cxx" "$CC" "$CXX" set_toolset "mm" "$CC" "$CXX" set_toolset "mxx" "$CC" "$CXX" set_toolset "ld" "$CXX" "$CC" "$LD" set_toolset "sh" "$CXX" "$CC" "$LD" set_toolset "ar" "$AR" "ar" toolchain_end # clang toolchain toolchain "clang" set_toolset "as" "clang" set_toolset "cc" "clang" set_toolset "cxx" "clang" "clang++" set_toolset "mm" "clang" set_toolset "mxx" "clang" "clang++" set_toolset "ld" "clang++" "clang" set_toolset "sh" "clang++" "clang" set_toolset "ar" "ar" toolchain_end # gcc toolchain toolchain "gcc" set_toolset "as" "gcc" set_toolset "cc" "gcc" set_toolset "cxx" "gcc" "g++" set_toolset "mm" "gcc" set_toolset "mxx" "gcc" "g++" set_toolset "ld" "g++" "gcc" set_toolset "sh" "g++" "gcc" set_toolset "ar" "ar" toolchain_end # mingw toolchain (x86_64) toolchain "x86_64_w64_mingw32" set_toolset "as" "x86_64-w64-mingw32-gcc" set_toolset "cc" "x86_64-w64-mingw32-gcc" set_toolset "cxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++" set_toolset "mm" "x86_64-w64-mingw32-gcc" set_toolset "mxx" "x86_64-w64-mingw32-gcc" "x86_64-w64-mingw32-g++" set_toolset "ld" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc" set_toolset "sh" "x86_64-w64-mingw32-g++" "x86_64-w64-mingw32-gcc" set_toolset "ar" "x86_64-w64-mingw32-ar" "ar" toolchain_end # mingw toolchain (i686) toolchain "i686_w64_mingw32" set_toolset "as" "i686-w64-mingw32-gcc" set_toolset "cc" "i686-w64-mingw32-gcc" set_toolset "cxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++" set_toolset "mm" "i686-w64-mingw32-gcc" set_toolset "mxx" "i686-w64-mingw32-gcc" "i686-w64-mingw32-g++" set_toolset "ld" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc" set_toolset "sh" "i686-w64-mingw32-g++" "i686-w64-mingw32-gcc" set_toolset "ar" "i686-w64-mingw32-ar" "ar" toolchain_end # aarch64 toolchain (aarch64) toolchain "aarch64_linux_gnu" set_toolset "as" "aarch64-linux-gnu-gcc" set_toolset "cc" "aarch64-linux-gnu-gcc" set_toolset "cxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++" set_toolset "mm" "aarch64-linux-gnu-gcc" set_toolset "mxx" "aarch64-linux-gnu-gcc" "aarch64-linux-gnu-g++" set_toolset "ld" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc" set_toolset "sh" "aarch64-linux-gnu-g++" "aarch64-linux-gnu-gcc" set_toolset "ar" "aarch64-linux-gnu-ar" "ar" toolchain_end # emcc toolchain (wasm32) toolchain "emcc" set_toolset "as" "emcc" set_toolset "cc" "emcc" set_toolset "cxx" "emcc" "em++" set_toolset "mm" "emcc" set_toolset "mxx" "emcc" "em++" set_toolset "ld" "em++" "emcc" set_toolset "sh" "em++" "emcc" set_toolset "ar" "emar" "ar" toolchain_end # cosmocc toolchain, e.g. ./configure --plat=linux --toolchain=cosmocc toolchain "cosmocc" set_toolset "as" "cosmocc" set_toolset "cc" "cosmocc" set_toolset "cxx" "cosmocc" "cosmoc++" set_toolset "mm" "cosmocc" set_toolset "mxx" "cosmocc" "cosmoc++" set_toolset "ld" "cosmoc++" "cosmocc" set_toolset "sh" "cosmoc++" "cosmocc" set_toolset "ar" "cosmoar" toolchain_end # check platform _check_platform() { if test "x${_target_plat}" = "x"; then _target_plat=${_target_plat_default} fi if test "x${_target_arch}" = "x"; then _target_arch=${_target_arch_default} fi if test "x${_target_mode}" = "x"; then _target_mode=${_target_mode_default} fi if test "x${_target_kind}" = "x"; then _target_kind=${_target_kind_default} fi echo "checking for platform ... ${_target_plat}" echo "checking for architecture ... ${_target_arch}" } # get toolchain compile command for gcc/clang _toolchain_compcmd_for_gcc_clang() { local program="${1}" local objectfile="${2}" local sourcefile="${3}" local flags="${4}" _ret="${program} -c ${flags} -o ${objectfile} ${sourcefile}" } # get toolchain link command for gcc/clang _toolchain_linkcmd_for_gcc_clang() { local toolkind="${1}" local program="${2}" local binaryfile="${3}" local objectfiles="${4}" local flags="${5}" if test_eq "${toolkind}" "sh"; then flags="-shared -fPIC ${flags}" fi _ret="${program} -o ${binaryfile} ${objectfiles} ${flags}" } # get toolchain link command for ar _toolchain_linkcmd_for_ar() { local toolkind="${1}" local program="${2}" local binaryfile="${3}" local objectfiles="${4}" local flags="${5}" _ret="${program} ${flags} ${binaryfile} ${objectfiles}" } # get toolchain compile command _toolchain_compcmd() { local sourcekind="${1}" local objectfile="${2}" local sourcefile="${3}" local flags="${4}" _get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local compcmd="" case "${toolname}" in gcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; gxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; clang) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; clangxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; emcc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; emxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; cosmocc) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; cosmocxx) _toolchain_compcmd_for_gcc_clang "${program}" "${objectfile}" "${sourcefile}" "${flags}"; compcmd="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac _ret="${compcmd}" } # get toolchain link command _toolchain_linkcmd() { local toolkind="${1}" local binaryfile="${2}" local objectfiles="${3}" local flags="${4}" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" case "${toolname}" in gcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; gxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; clang) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; clangxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; emcc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; emxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; cosmocc) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; cosmocxx) _toolchain_linkcmd_for_gcc_clang "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; ar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; emar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; cosmoar) _toolchain_linkcmd_for_ar "${toolkind}" "${program}" "${binaryfile}" "${objectfiles}" "${flags}"; linkcmd="${_ret}";; *) raise "unknown toolname(${toolname})!" ;; esac _ret="${linkcmd}" } # try make _toolchain_try_make() { local program="${1}" if _os_runv "${program}" "--version"; then return 0 fi return 1 } # try ninja _toolchain_try_ninja() { local program="${1}" if _os_runv "${program}" "--version"; then return 0 fi return 1 } # try gcc _toolchain_try_gcc() { if test "x${_toolchain_try_gcc_result}" = "xok"; then return 0 elif test "x${_toolchain_try_gcc_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_gcc_result="ok" return 0 fi _toolchain_try_gcc_result="no" return 1 } # try g++ _toolchain_try_gxx() { if test "x${_toolchain_try_gxx_result}" = "xok"; then return 0 elif test "x${_toolchain_try_gxx_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_gxx_result="ok" return 0 fi _toolchain_try_gxx_result="no" return 1 } # try clang _toolchain_try_clang() { if test "x${_toolchain_try_clang_result}" = "xok"; then return 0 elif test "x${_toolchain_try_clang_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_clang_result="ok" return 0 fi _toolchain_try_clang_result="no" return 1 } # try clang++ _toolchain_try_clangxx() { if test "x${_toolchain_try_clangxx_result}" = "xok"; then return 0 elif test "x${_toolchain_try_clangxx_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_clangxx_result="ok" return 0 fi _toolchain_try_clangxx_result="no" return 1 } # try ar _toolchain_try_ar() { local kind="${1}" local program="${2}" # generate the source file _os_tmpfile local tmpfile="${_ret}" local objectfile="${tmpfile}.o" local libraryfile="${tmpfile}.a" echo "" > "${objectfile}" # try linking it local ok=false if _os_runv "${program}" "-cr" "${libraryfile}" "${objectfile}"; then ok=true fi # remove files _os_tryrm "${objectfile}" _os_tryrm "${libraryfile}" if ${ok}; then return 0 fi return 1 } # try cosmoar _toolchain_try_cosmoar() { if test "x${_toolchain_try_cosmoar_result}" = "xok"; then return 0 elif test "x${_toolchain_try_cosmoar_result}" = "xno"; then return 1 fi local kind="${1}" local program="${2}" if _os_runv "${program}" "--version"; then _toolchain_try_cosmoar_result="ok" return 0 fi _toolchain_try_cosmoar_result="no" return 1 } # try program _toolchain_try_program() { local toolchain="${1}" local kind="${2}" local program="${3}" local ok=false path_toolname "${program}"; local toolname="${_ret}" case "${toolname}" in gcc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;; gxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;; clang) _toolchain_try_clang "${kind}" "${program}" && ok=true;; clangxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;; emcc) _toolchain_try_clang "${kind}" "${program}" && ok=true;; emxx) _toolchain_try_clangxx "${kind}" "${program}" && ok=true;; cosmocc) _toolchain_try_gcc "${kind}" "${program}" && ok=true;; cosmocxx) _toolchain_try_gxx "${kind}" "${program}" && ok=true;; ar) _toolchain_try_ar "${kind}" "${program}" && ok=true;; emar) _toolchain_try_ar "${kind}" "${program}" && ok=true;; cosmoar) _toolchain_try_cosmoar "${kind}" "${program}" && ok=true;; *) raise "unknown toolname(${toolname})!" ;; esac if ${ok}; then vprint "checking for ${program} ... ok" return 0 fi vprint "checking for ${program} ... no" return 1 } # try toolset _toolchain_try_toolset() { local toolchain=${1} local kind=${2} local description=${3} local indices="0 1 2 3 4 5" for idx in ${indices}; do local key="${kind}" if test_nq "${idx}" "0"; then key="${key}_${idx}" fi _get_toolchain_toolset "${toolchain}" "${key}"; local program="${_ret}" if test_nz "${program}"; then if _toolchain_try_program "${toolchain}" "${kind}" "${program}"; then _set_toolchain_toolset "${toolchain}" "${kind}" "${program}" echo "checking for the ${description} (${kind}) ... ${program}" return 0 fi fi done return 1 } # try toolchain _toolchain_try() { local toolchain=${1} vprint "checking for $toolchain toolchain ..." if _toolchain_try_toolset "${toolchain}" "cc" "c compiler" && _toolchain_try_toolset "${toolchain}" "cxx" "c++ compiler" && _toolchain_try_toolset "${toolchain}" "as" "assembler" && _toolchain_try_toolset "${toolchain}" "mm" "objc compiler" && _toolchain_try_toolset "${toolchain}" "mxx" "objc++ compiler" && _toolchain_try_toolset "${toolchain}" "ld" "linker" && _toolchain_try_toolset "${toolchain}" "ar" "static library archiver" && _toolchain_try_toolset "${toolchain}" "sh" "shared library linker"; then return 0 fi return 1 } # detect make _toolchain_detect_make() { if test "x${_make_program}" = "x"; then _make_program=${_make_program_default} fi if _toolchain_try_make "${_make_program}"; then echo "checking for make ... ok" else echo "checking for make ... no" raise "make not found!" fi } # detect ninja _toolchain_detect_ninja() { if test "x${_ninja_program}" = "x"; then _ninja_program=${_ninja_program_default} fi if _toolchain_try_ninja "${_ninja_program}"; then echo "checking for ninja ... ok" else echo "checking for ninja ... no" raise "ninja not found!" fi } # detect build backend _toolchain_detect_backend() { if test "x${project_generator}" = "xgmake"; then _toolchain_detect_make elif test "x${project_generator}" = "xninja"; then _toolchain_detect_ninja fi } # detect toolchain _toolchain_detect() { # detect build backend _toolchain_detect_backend # detect toolchains local toolchains="${1}" if test "x${toolchains}" = "x"; then if is_plat "macosx"; then toolchains="envs clang gcc" elif is_plat "mingw"; then if is_arch "i386"; then toolchains="i686_w64_mingw32" else toolchains="x86_64_w64_mingw32" fi elif is_plat "wasm"; then toolchains="emcc" elif is_plat "linux" && ! is_arch "${os_arch}"; then toolchains="envs" if is_arch "arm64"; then toolchains="${toolchains} aarch64_linux_gnu" fi else toolchains="envs gcc clang" fi fi for toolchain in ${toolchains}; do if _toolchain_try "$toolchain"; then _target_toolchain=${toolchain} break fi done } # check toolchain _check_toolchain() { local toolchain=${_target_toolchain} _target_toolchain="" _toolchain_detect ${toolchain} if test "x${_target_toolchain}" != "x"; then echo "checking for toolchain ... ${_target_toolchain}" else echo "checking for toolchain ... no" raise "toolchain not found!" fi } # get function code # # sigsetjmp # sigsetjmp((void*)0, 0) # _get_funccode() { local func="${1}" local code="" if string_contains "${func}" "("; then code="${func}" else code="typedef void (*func_t)(); volatile func_t p${func} = (func_t)${func}; while (p${func}) {break;};" fi _ret="${code}" } # generate cxsnippets source code _generate_cxsnippets_sourcecode() { local funcs="${1}" local includes="${2}" local types="${3}" local snippets="${4}" local snippet_includes="" for include in $includes; do snippet_includes="${snippet_includes}#include \"${include}\"\n" done local snippet_types="" for type in $types; do string_replace "${type}" '[^a-zA-Z]' "_"; local typevar="${_ret}" snippet_types="${snippet_types}typedef ${type} __type_${typevar};\n" done local snippet_funcs="" for func in $funcs; do _get_funccode "${func}"; func="${_ret}" snippet_funcs="${snippet_funcs}${func}\n " done local snippets_code="" if test_nz "${snippet_includes}"; then snippets_code="${snippets_code}${snippet_includes}\n" fi if test_nz "${snippet_types}"; then snippets_code="${snippets_code}${snippet_types}\n" fi if test_nz "${snippets}"; then snippets_code="${snippets_code}${snippets}\n" fi _ret=' '"${snippets_code}"'int main(int argc, char** argv) { '"${snippet_funcs}"' return 0; }' } # check cxsnippets _check_cxsnippets() { local name="${1}" local kind="${2}" _get_option_item "${name}" "${kind}funcs"; local funcs="${_ret}" _get_option_item "${name}" "${kind}includes"; local includes="${_ret}" _get_option_item "${name}" "${kind}types"; local types="${_ret}" _get_option_item "${name}" "${kind}snippets"; local snippets="${_ret}" if test_z "${funcs}" && test_z "${includes}" && test_z "${types}" && test_z "${snippets}"; then return 0 fi # get c/c++ extension local extension=".c" local sourcekind="cc" if test_eq "${kind}" "cxx"; then extension=".cpp" sourcekind="cxx" fi # generate source code _generate_cxsnippets_sourcecode "${funcs}" "${includes}" "${types}" "${snippets}"; local sourcecode="${_ret}" dprint "${sourcecode}" # generate the source file _os_tmpfile local tmpfile="${_ret}" local sourcefile="${tmpfile}${extension}" local objectfile="${tmpfile}.o" local binaryfile="${tmpfile}.bin" print "${sourcecode}" > "${sourcefile}" # try compiling it local ok=false if ! ${ok}; then local compflags="" _get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local itemnames="languages warnings optimizes defines undefines includedirs" for itemname in ${itemnames}; do _get_option_abstract_flags "${name}" "${sourcekind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then _split_flags "${flags}"; flags="${_ret}" compflags="${compflags} ${flags}" fi done local flagnames="cxflags" if test_eq "${sourcekind}" "cxx"; then flagnames="${flagnames} cxxflags" else flagnames="${flagnames} cflags" fi for flagname in $flagnames; do _get_option_item "${name}" "${flagname}"; local flags="${_ret}" if test_nz "${flags}"; then compflags="${compflags} ${flags}" fi done if test_eq "${sourcekind}" "cxx"; then if test_nz "${CXXFLAGS}"; then compflags="${compflags} ${CXXFLAGS}" fi else if test_nz "${CFLAGS}"; then compflags="${compflags} ${CFLAGS}" fi fi if test_nz "${CPPFLAGS}"; then compflags="${compflags} ${CPPFLAGS}" fi _toolchain_compcmd "${sourcekind}" "${objectfile}" "${sourcefile}" "${compflags}"; local compcmd="${_ret}" if ${xmake_sh_diagnosis}; then print "> ${compcmd}" fi if _os_runv ${compcmd}; then ok=true fi fi # try linking it _get_option_item "${name}" "links"; local links="${_ret}" _get_option_item "${name}" "syslinks"; local syslinks="${_ret}" _get_option_item "${name}" "ldflags"; local ldflags="${_ret}" if test_nz "${syslinks}"; then links="${links} ${syslinks}" fi if ${ok} && (test_nz "${links}" || test_nz "${ldflags}"); then local toolkind="ld" _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" local itemnames="linkdirs links syslinks" local linkflags="" for itemname in ${itemnames}; do _get_option_abstract_flags "${name}" "${toolkind}" "${toolname}" "${itemname}"; local flags="${_ret}" if test_nz "${flags}"; then _split_flags "${flags}"; flags="${_ret}" linkflags="${linkflags} ${flags}" fi done _get_option_item "${name}" "ldflags"; local flags="${_ret}" if test_nz "${flags}"; then linkflags="${linkflags} ${flags}" fi if test_nz "${LDFLAGS}"; then linkflags="${linkflags} ${LDFLAGS}" fi _toolchain_linkcmd "${toolkind}" "${binaryfile}" "${objectfile}" "${linkflags}"; local linkcmd="${_ret}" if ${xmake_sh_diagnosis}; then print "> ${linkcmd}" fi if _os_runv ${linkcmd}; then ok=true else ok=false fi fi # trace if ${xmake_sh_verbose} || ${xmake_sh_diagnosis}; then if test_nz "${includes}"; then print "> checking for ${kind} includes(${includes})" fi if test_nz "${types}"; then print "> checking for ${kind} types(${types})" fi if test_nz "${funcs}"; then print "> checking for ${kind} funcs(${funcs})" fi if test_nz "${links}"; then print "> checking for ${kind} links(${links})" fi fi # remove files _os_tryrm "${sourcefile}" _os_tryrm "${objectfile}" _os_tryrm "${binaryfile}" if ${ok}; then return 0 fi return 1 } # check csnippets _check_csnippets() { local name="${1}" if _check_cxsnippets "${name}" "c"; then return 0 fi return 1 } # check cxxsnippets _check_cxxsnippets() { local name="${1}" if _check_cxsnippets "${name}" "cxx"; then return 0 fi return 1 } # check option _check_option() { local name="${1}" _get_option_value "${name}"; local value="${_ret}" _get_option_item "${name}" "default"; local default="${_ret}" if test_nz "${value}"; then if _is_enabled "${value}"; then return 0 else return 1 fi elif test_nz "${default}"; then if _is_enabled "${default}"; then return 0 else return 1 fi else _get_option_item "${name}" "before_check"; local before_check="${_ret}" if test_nz "${before_check}"; then eval ${before_check} fi if _check_csnippets "${name}" && _check_cxxsnippets "${name}"; then return 0 fi fi return 1 } # check options _check_options() { _get_options_for_checking; local options="${_ret}" for name in $options; do if _check_option "$name"; then echo "checking for ${name} .. ok" _set_option_value "${name}" true else echo "checking for ${name} .. no" _set_option_value "${name}" false fi done } # check all _check_all() { _check_platform _check_toolchain _check_options } _check_all #----------------------------------------------------------------------------- # init builtin variables, e.g. add_headerfiles "${buildir}/config.h" # projectdir="${xmake_sh_projectdir}" if path_is_absolute "${xmake_sh_buildir}"; then buildir="${xmake_sh_buildir}" else buildir="${xmake_sh_projectdir}/${xmake_sh_buildir}" fi plat="${_target_plat}" arch="${_target_arch}" mode="${_target_mode}" kind="${_target_kind}" #----------------------------------------------------------------------------- # load project targets # # load targets _load_targets() { echo "analyzing project configuration .." _loading_options=false _loading_toolchains=false _loading_targets=true _xmake_sh_option_current="" _xmake_sh_target_current="" _xmake_sh_toolchain_current="" local file=${xmake_sh_projectdir}/xmake.sh if test -f "${file}"; then includes "${file}" else # include all xmake.sh files in next sub-directories _os_find "${xmake_sh_projectdir}" "xmake.sh" 2; local files="${_ret}" for file in ${files}; do includes "${file}" done fi } _load_targets # get toolset kinds for all targets # e.g. cc cxx as mm mxx ld sh ar _get_targets_toolkinds() { if test_z "${_targets_toolkinds_dedup}"; then _dedup "${_targets_toolkinds}"; _targets_toolkinds_dedup="${_ret}" fi _ret="${_targets_toolkinds_dedup}" } #----------------------------------------------------------------------------- # generate configfiles # # vprint config variable in `${name}` _vprint_configvar_value() { local name="${1}" local value="${2}" vprint " > replace ${name} -> ${value}" } # vprint config variable in `${define name}` _vprint_configvar_define() { local name="${1}" local value="${2}" if test_z "${value}"; then vprint " > replace ${name} -> /* #undef ${name} */" elif test_eq "${value}" "1" || test_eq "${value}" "true"; then vprint " > replace ${name} -> #define ${name} 1" elif test_eq "${value}" "0" || test_eq "${value}" "false"; then vprint " > replace ${name} -> /*#define ${name} 0*/" else vprint " > replace ${name} -> #define ${name} ${value}" fi } # replace config variable in `${define name}` _replace_configvar_define() { local name="${1}" local value="${2}" if test_z "${value}"; then _ret="s/\${define ${name}}/\/*#undef ${name}*\//g" elif test_eq "${value}" "1" || test_eq "${value}" "true"; then _ret="s/\${define ${name}}/#define ${name} 1/g" elif test_eq "${value}" "0" || test_eq "${value}" "false"; then _ret="s/\${define ${name}}/\/*#define ${name} 0*\//g" else _ret="s/\${define ${name}}/#define ${name} ${value}/g" fi } # replace config variable in `${name}` _replace_configvar_value() { local name="${1}" local value="${2}" _ret="s@\${${name}}@${value}@g" } # generate configfile for the given target _generate_configfile() { local target="${1}" local configfile_in="${2}" _get_target_item "${target}" "configdir"; local configdir="${_ret}" if test_z "${configdir}"; then path_directory configfile_in; configdir="${_ret}" fi if ! test -d "${configdir}"; then mkdir -p "${configdir}" fi path_basename "${configfile_in}"; local filename="${_ret}" local configfile="${configdir}/${filename}" echo "generating ${configfile} .." # replace builtin variables local patterns="" local target_os="" if is_plat "mingw"; then target_os="windows" else target_os="${_target_plat}" fi string_toupper ${target_os}; target_os="${_ret}" _vprint_configvar_value "OS" "${target_os}" _replace_configvar_value "OS" "${target_os}"; patterns="${_ret};${patterns}" # replace version _get_target_item "${target}" "version"; local version="${_ret}" _get_target_item "${target}" "version_build"; local version_build="${_ret}" string_split "${version}" "." local version_major="${_ret}" local version_minor="${_ret2}" local version_alter="${_ret3}" if test_nz "${version}"; then _vprint_configvar_value "VERSION" "${version}" _replace_configvar_value "VERSION" "${version}"; patterns="${_ret};${patterns}" fi if test_nz "${version_major}"; then _vprint_configvar_value "VERSION_MAJOR" "${version_major}" _replace_configvar_value "VERSION_MAJOR" "${version_major}"; patterns="${_ret};${patterns}" fi if test_nz "${version_minor}"; then _vprint_configvar_value "VERSION_MINOR" "${version_minor}" _replace_configvar_value "VERSION_MINOR" "${version_minor}"; patterns="${_ret};${patterns}" fi if test_nz "${version_alter}"; then _vprint_configvar_value "VERSION_ALTER" "${version_alter}" _replace_configvar_value "VERSION_ALTER" "${version_alter}"; patterns="${_ret};${patterns}" fi if test_nz "${version_build}"; then _os_date "${version_build}"; version_build="${_ret}" _vprint_configvar_value "VERSION_BUILD" "${version_build}" _replace_configvar_value "VERSION_BUILD" "${version_build}"; patterns="${_ret};${patterns}" fi # replace git variables local content="" content=$(cat "${configfile_in}") if string_contains "${content}" "GIT_"; then _os_iorunv "git" "describe" "--tags"; local git_tag="${_ret}" _vprint_configvar_value "GIT_TAG" "${git_tag}" _replace_configvar_value "GIT_TAG" "${git_tag}"; patterns="${_ret};${patterns}" _os_iorunv "git" "describe" "--tags" "--long"; local git_tag_long="${_ret}" _vprint_configvar_value "GIT_TAG_LONG" "${git_tag_long}" _replace_configvar_value "GIT_TAG_LONG" "${git_tag_long}"; patterns="${_ret};${patterns}" _os_iorunv "git" "rev-parse" "--abbrev-ref" "HEAD"; local git_branch="${_ret}" _vprint_configvar_value "GIT_BRANCH" "${git_branch}" _replace_configvar_value "GIT_BRANCH" "${git_branch}"; patterns="${_ret};${patterns}" _os_iorunv "git" "rev-parse" "--short" "HEAD"; local git_commit="${_ret}" _vprint_configvar_value "GIT_COMMIT" "${git_commit}" _replace_configvar_value "GIT_COMMIT" "${git_commit}"; patterns="${_ret};${patterns}" _os_iorunv "git" "rev-parse" "HEAD"; local git_commit_long="${_ret}" _vprint_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}" _replace_configvar_value "GIT_COMMIT_LONG" "${git_commit_long}"; patterns="${_ret};${patterns}" _os_iorunv "log" "-1" "--date=format:%Y%m%d%H%M%S" "--format=%ad"; local git_commit_date="${_ret}" _vprint_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}" _replace_configvar_value "GIT_COMMIT_DATE" "${git_commit_date}"; patterns="${_ret};${patterns}" fi # replace configvars in target local count=0 local configfile_dst="${configfile}" _os_tmpfile; local tmpfile="${_ret}" cp "${configfile_in}" "${tmpfile}" _get_target_item "${target}" "configvars"; local configvars="${_ret}" for name in ${configvars}; do _get_target_item "${target}" "configvar_${name}"; local value="${_ret}" _vprint_configvar_define "${name}" "${value}" _vprint_configvar_value "${name}" "${value}" _replace_configvar_define "${name}" "${value}"; patterns="${_ret};${patterns}" _replace_configvar_value "${name}" "${value}"; patterns="${_ret};${patterns}" count=$((count + 1)) # do replace if test_eq "$count" "10"; then _io_replace_file "${tmpfile}" "${configfile}" "${patterns}" local swapfile="${tmpfile}" tmpfile="${configfile}" configfile="${swapfile}" patterns="" count=0 fi done # do replace (left) if test_nz "${patterns}"; then _io_replace_file "${tmpfile}" "${configfile}" "${patterns}" local swapfile="${tmpfile}" tmpfile="${configfile}" configfile="${swapfile}" patterns="" count=0 fi # replace fallback patterns='s/${define \(.*\)}/\/*#undef \1*\//g;' _io_replace_file "${tmpfile}" "${configfile}" "${patterns}" if test_nq "${configfile}" "${configfile_dst}"; then cp "${configfile}" "${configfile_dst}" fi echo "${configfile_dst} is generated!" } # generate configfiles _generate_configfiles() { for target in ${_xmake_sh_targets}; do _get_target_item "${target}" "configfiles"; local configfiles="${_ret}" for configfile in ${configfiles}; do _generate_configfile "${target}" "${configfile}" done done } _generate_configfiles #----------------------------------------------------------------------------- # generate gmake file # _gmake_begin() { echo "generating makefile .." } _gmake_add_header() { echo "# this is the build file for this project # it is autogenerated by the xmake.sh build system. # do not edit by hand. " > "${xmake_sh_makefile}" } _gmake_add_switches() { echo "ifneq (\$(VERBOSE),1)" >> "${xmake_sh_makefile}" echo "VV=@" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" echo "ifeq (\$(PREFIX),)" >> "${xmake_sh_makefile}" echo "PREFIX=${_install_prefix_default}" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" echo "INSTALLDIR:=\$(DESTDIR)" >> "${xmake_sh_makefile}" echo "ifneq (\$(PREFIX),)" >> "${xmake_sh_makefile}" echo "ifneq (\$(INSTALLDIR),)" >> "${xmake_sh_makefile}" echo "PREFIX_:=\$(patsubst /%,%,\$(PREFIX))" >> "${xmake_sh_makefile}" echo "INSTALLDIR:=\$(INSTALLDIR)/\$(PREFIX_)" >> "${xmake_sh_makefile}" echo "else" >> "${xmake_sh_makefile}" echo "INSTALLDIR:=\$(PREFIX)" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "endif" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" } _gmake_add_flags() { _get_targets_toolkinds; local kinds="${_ret}" for target in ${_xmake_sh_targets}; do for kind in ${kinds}; do _get_target_flags "${target}" "${kind}"; local flags="${_ret}" _get_flagname "${kind}"; local flagname="${_ret}" local key="${target}_${flagname}" echo "${key}=${flags}" >> "${xmake_sh_makefile}" done echo "" >> "${xmake_sh_makefile}" done } _gmake_add_toolchains() { _get_targets_toolkinds; local kinds="${_ret}" for kind in ${kinds}; do _get_toolchain_toolset "${_target_toolchain}" "${kind}"; local program="${_ret}" local key="${kind}" echo "${key}=${program}" >> "${xmake_sh_makefile}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_build_object_for_gcc_clang() { local kind="${1}" local sourcefile="${2}" local objectfile="${3}" local flagname="${4}" path_directory "${objectfile}"; local objectdir="${_ret}" print "\t@mkdir -p ${objectdir}" >> "${xmake_sh_makefile}" print "\t\$(VV)\$(${kind}) -c \$(${flagname}) -o ${objectfile} ${sourcefile}" >> "${xmake_sh_makefile}" } _gmake_add_build_object() { local target=${1} local sourcefile="${2}" local objectfile="${3}" path_sourcekind "${sourcefile}"; local sourcekind="${_ret}" _get_toolchain_toolset "${_target_toolchain}" "${sourcekind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" _get_flagname "${sourcekind}"; local flagname="${_ret}" flagname="${target}_${flagname}" echo "${objectfile}: ${sourcefile}" >> "${xmake_sh_makefile}" print "\t@echo compiling.${_target_mode} ${sourcefile}" >> "${xmake_sh_makefile}" case "${toolname}" in gcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; gxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; clang) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; clangxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; emcc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; emxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; cosmocc) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; cosmocxx) _gmake_add_build_object_for_gcc_clang "${sourcekind}" "${sourcefile}" "${objectfile}" "${flagname}";; *) raise "unknown toolname(${toolname})!" ;; esac echo "" >> "${xmake_sh_makefile}" } _gmake_add_build_objects() { local target=${1} _get_target_sourcefiles "${target}"; local sourcefiles="${_ret}" for sourcefile in ${sourcefiles}; do _get_target_objectfile "${target}" "${sourcefile}"; local objectfile="${_ret}" _gmake_add_build_object "${target}" "${sourcefile}" "${objectfile}" done } _gmake_add_build_target_for_gcc_clang() { local kind="${1}" local targetfile="${2}" local objectfiles="${3}" local flagname="${4}" path_directory "${targetfile}"; local targetdir="${_ret}" print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}" print "\t\$(VV)\$(${kind}) -o ${targetfile} ${objectfiles} \$(${flagname})" >> "${xmake_sh_makefile}" } _gmake_add_build_target_for_ar() { local kind="${1}" local targetfile="${2}" local objectfiles="${3}" local flagname="${4}" path_directory "${targetfile}"; local targetdir="${_ret}" print "\t@mkdir -p ${targetdir}" >> "${xmake_sh_makefile}" print "\t\$(VV)\$(${kind}) \$(${flagname}) ${flags} ${targetfile} ${objectfiles}" >> "${xmake_sh_makefile}" } _gmake_add_build_target() { local target=${1} _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_file "${target}"; local targetfile="${_ret}" _get_target_item "${target}" "deps"; local deps="${_ret}" _get_target_objectfiles "${target}"; local objectfiles="${_ret}" # get linker _get_target_item "${target}" "kind"; local targetkind="${_ret}" local toolkind="" case "${targetkind}" in binary) toolkind="ld";; static) toolkind="ar";; shared) toolkind="sh";; *) raise "unknown targetkind(${targetkind})!" ;; esac _get_toolchain_toolset "${_target_toolchain}" "${toolkind}"; local program="${_ret}" path_toolname "${program}"; local toolname="${_ret}" # get linker flags _get_flagname "${toolkind}"; local flagname="${_ret}" flagname="${target}_${flagname}" # get depfiles local dep="" local depfiles="" for dep in ${deps}; do _get_target_file "${dep}"; local depfile="${_ret}" if test_nz "${depfiles}"; then depfiles="${depfiles} ${depfile}" else depfiles="${depfile}" fi done # link target echo "${target}: ${targetfile}" >> "${xmake_sh_makefile}" echo "${targetfile}: ${depfiles}${objectfiles}" >> "${xmake_sh_makefile}" print "\t@echo linking.${_target_mode} ${targetfile}" >> "${xmake_sh_makefile}" case "${toolname}" in gcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; gxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; clang) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; clangxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; emcc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; emxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; cosmocc) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; cosmocxx) _gmake_add_build_target_for_gcc_clang "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; ar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; emar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; cosmoar) _gmake_add_build_target_for_ar "${toolkind}" "${targetfile}" "${objectfiles}" "${flagname}";; *) raise "unknown toolname(${toolname})!" ;; esac # @see https://github.com/tboox/tbox/issues/214 if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_filename "${target}"; local filename="${_ret}" _get_target_extension "${target}"; local extension="${_ret}" local targetfile_with_version="${targetdir}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${filename}"; local basename="${_ret}" targetfile_with_version="${targetdir}/${basename}.${version}${extension}" fi local targetfile_with_soname="${targetdir}/${soname}" path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}" if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}" print "\t@cd ${targetdir} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}" fi fi fi # end echo "" >> "${xmake_sh_makefile}" # build objects _gmake_add_build_objects "${target}" } _gmake_add_build_targets() { local target="" local defaults="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then defaults="${defaults} ${target}" fi done echo "default:${defaults}" >> "${xmake_sh_makefile}" echo "all:${_xmake_sh_targets}" >> "${xmake_sh_makefile}" echo ".PHONY: default all" >> "${xmake_sh_makefile}" echo "" >> "${xmake_sh_makefile}" for target in ${_xmake_sh_targets}; do _gmake_add_build_target "${target}" done } _gmake_add_build() { _gmake_add_build_targets } _gmake_add_run_target() { local target=${1} _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_file "${target}"; local targetfile="${_ret}" if is_plat "macosx"; then print "\t@DYLD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}" elif is_plat "linux" "bsd"; then print "\t@LD_LIBRARY_PATH=${targetdir} ${targetfile}" >> "${xmake_sh_makefile}" else print "\t@${targetfile}" >> "${xmake_sh_makefile}" fi } _gmake_add_run_targets() { local target="" local targets="" for target in ${_xmake_sh_targets}; do _get_target_item "${target}" "kind"; local kind="${_ret}" if test "x${kind}" = "xbinary"; then if _is_target_default "${target}"; then targets="${targets} ${target}" fi fi done echo "run:${targets}" >> "${xmake_sh_makefile}" for target in ${targets}; do _gmake_add_run_target "${target}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_run() { _gmake_add_run_targets } _gmake_add_clean_target() { local target=${1} local objectfile="" _get_target_file "${target}"; local targetfile="${_ret}" _get_target_objectfiles "${target}"; local objectfiles="${_ret}" print "\t@rm ${targetfile}" >> "${xmake_sh_makefile}" for objectfile in ${objectfiles}; do print "\t@rm ${objectfile}" >> "${xmake_sh_makefile}" done # @see https://github.com/tboox/tbox/issues/214 _get_targetdir "${target}"; local targetdir="${_ret}" _get_target_item "${target}" "kind"; local targetkind="${_ret}" if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_filename "${target}"; local filename="${_ret}" _get_target_extension "${target}"; local extension="${_ret}" local targetfile_with_version="${targetdir}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${filename}"; local basename="${_ret}" targetfile_with_version="${targetdir}/${basename}.${version}${extension}" fi local targetfile_with_soname="${targetdir}/${soname}" print "\t@if test -f ${targetfile_with_soname}; then rm ${targetfile_with_soname}; fi" >> "${xmake_sh_makefile}" print "\t@if test -f ${targetfile_with_version}; then rm ${targetfile_with_version}; fi" >> "${xmake_sh_makefile}" fi fi } _gmake_add_clean_targets() { local target="" local targets="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then targets="${targets} ${target}" fi done echo "clean:${targets}" >> "${xmake_sh_makefile}" for target in ${targets}; do _gmake_add_clean_target "${target}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_clean() { _gmake_add_clean_targets } _gmake_add_install_target() { local target=${1} _get_target_file "${target}"; local targetfile="${_ret}" path_filename "${targetfile}"; local filename="${_ret}" _get_target_item "${target}" "installdir"; local installdir="${_ret}" _get_target_item "${target}" "kind"; local targetkind="${_ret}" if test_z "${installdir}"; then installdir="\$(INSTALLDIR)" fi # before install _get_target_item "${target}" "before_install"; local before_install="${_ret}" if test_nz "${before_install}"; then eval ${before_install} "\${target}" "\${installdir}" fi # @see https://github.com/tboox/tbox/issues/214 install_for_soname=false if test_eq "${targetkind}" "shared"; then _get_target_item "${target}" "version"; local version="${_ret}" _get_target_soname "${target}"; local soname="${_ret}" if test_nz "${soname}" && test_nz "${version}"; then _get_target_extension "${target}"; local extension="${_ret}" string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}" local targetfile_with_version="${_install_libdir_default}/${filename}.${version}" if test_eq "${extension}" ".dylib"; then path_basename "${filename}"; local basename="${_ret}" targetfile_with_version="${_install_libdir_default}/${basename}.${version}${extension}" fi local targetfile_with_soname="${_install_libdir_default}/${soname}" path_filename "${targetfile_with_version}"; local targetfilename_with_version="${_ret}" if test_nq "${soname}" "${filename}" && test_nq "${soname}" "${targetfilename_with_version}"; then install_for_soname=true fi fi fi # install target file if test_eq "${targetkind}" "binary"; then string_replace "${_install_bindir_default}" "\${prefix}" "${installdir}"; _install_bindir_default="${_ret}" print "\t@echo installing ${targetfile} to ${_install_bindir_default}" >> "${xmake_sh_makefile}" print "\t@mkdir -p ${_install_bindir_default}" >> "${xmake_sh_makefile}" print "\t@cp -p ${targetfile} ${_install_bindir_default}/${filename}" >> "${xmake_sh_makefile}" elif ${install_for_soname}; then string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}" print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@cp -p ${targetfile} ${targetfile_with_version}" >> "${xmake_sh_makefile}" print "\t@cd ${_install_libdir_default} && ln -sf ${targetfilename_with_version} ${soname} && ln -sf ${soname} ${filename}" >> "${xmake_sh_makefile}" elif test_eq "${targetkind}" "static" || test_eq "${targetkind}" "shared"; then string_replace "${_install_libdir_default}" "\${prefix}" "${installdir}"; _install_libdir_default="${_ret}" print "\t@echo installing ${targetfile} to ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@mkdir -p ${_install_libdir_default}" >> "${xmake_sh_makefile}" print "\t@cp -p ${targetfile} ${_install_libdir_default}/${filename}" >> "${xmake_sh_makefile}" fi # install header files _get_target_item "${target}" "headerfiles"; local headerfiles="${_ret}" if test_nz "${headerfiles}"; then string_replace "${_install_includedir_default}" "\${prefix}" "${installdir}"; _install_includedir_default="${_ret}" local srcheaderfile="" local includedir="${_install_includedir_default}" for srcheaderfile in ${headerfiles}; do string_split "${srcheaderfile}" ":" local srcheaderfile="${_ret}" local rootdir="${_ret2}" local prefixdir="${_ret3}" local filename="${_ret4}" if test_z "${filename}"; then path_filename "${srcheaderfile}"; filename="${_ret}" fi local dstheaderdir="${includedir}" if test_nz "${prefixdir}"; then dstheaderdir="${dstheaderdir}/${prefixdir}" fi local dstheaderfile="${dstheaderdir}/${filename}" if test_nz "${rootdir}"; then path_relative "${rootdir}" "${srcheaderfile}"; local subfile="${_ret}" dstheaderfile="${dstheaderdir}/${subfile}" fi path_directory "${dstheaderfile}"; dstheaderdir="${_ret}" print "\t@mkdir -p ${dstheaderdir}" >> "${xmake_sh_makefile}" print "\t@cp -p ${srcheaderfile} ${dstheaderfile}" >> "${xmake_sh_makefile}" done fi # install user files _get_target_item "${target}" "installfiles"; local installfiles="${_ret}" if test_nz "${installfiles}"; then local srcinstallfile="" for srcinstallfile in ${installfiles}; do string_split "${srcinstallfile}" ":" local srcinstallfile="${_ret}" local rootdir="${_ret2}" local prefixdir="${_ret3}" local filename="${_ret4}" if test_z "${filename}"; then path_filename "${srcinstallfile}"; filename="${_ret}" fi local dstinstalldir="${installdir}" if test_nz "${prefixdir}"; then dstinstalldir="${dstinstalldir}/${prefixdir}" fi local dstinstallfile="${dstinstalldir}/${filename}" if test_nz "${rootdir}"; then path_relative "${rootdir}" "${srcinstallfile}"; local subfile="${_ret}" dstinstallfile="${dstinstalldir}/${subfile}" fi path_directory "${dstinstallfile}"; dstinstalldir="${_ret}" print "\t@mkdir -p ${dstinstalldir}" >> "${xmake_sh_makefile}" print "\t@cp -p ${srcinstallfile} ${dstinstallfile}" >> "${xmake_sh_makefile}" done fi # after install _get_target_item "${target}" "after_install"; local after_install="${_ret}" if test_nz "${after_install}"; then eval ${after_install} "\${target}" "\${installdir}" fi } _gmake_add_install_targets() { local target="" local targets="" for target in ${_xmake_sh_targets}; do if _is_target_default "${target}"; then targets="${targets} ${target}" fi done echo "install:${targets}" >> "${xmake_sh_makefile}" for target in ${targets}; do _gmake_add_install_target "${target}" done echo "" >> "${xmake_sh_makefile}" } _gmake_add_install() { _gmake_add_install_targets } _gmake_done() { echo "makefile is generated!" if "${xmake_sh_diagnosis}"; then cat "${xmake_sh_makefile}" fi } # generate build file for gmake _generate_for_gmake() { _gmake_begin _gmake_add_header _gmake_add_switches _gmake_add_toolchains _gmake_add_flags _gmake_add_build _gmake_add_clean _gmake_add_install _gmake_add_run _gmake_done } #----------------------------------------------------------------------------- # generate ninja file # # generate build file for ninja _generate_for_ninja() { raise "Ninja generator has been not supported!" } #----------------------------------------------------------------------------- # generate build file # _generate_build_file() { if test_eq "${project_generator}" "gmake"; then _generate_for_gmake elif test_eq "${project_generator}" "ninja"; then _generate_for_ninja else raise "unknown generator: ${project_generator}" fi } _generate_build_file tbox-1.7.6/src/000077500000000000000000000000001467117505400133025ustar00rootroot00000000000000tbox-1.7.6/src/demo/000077500000000000000000000000001467117505400142265ustar00rootroot00000000000000tbox-1.7.6/src/demo/algorithm/000077500000000000000000000000001467117505400162145ustar00rootroot00000000000000tbox-1.7.6/src/demo/algorithm/find.c000066400000000000000000000107211467117505400173010ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * test */ static tb_void_t tb_find_int_test() { __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // make for (i = 0; i < n; i++) data[i] = i; // find tb_size_t itor = tb_iterator_tail(iterator); tb_hong_t time = tb_mclock(); for (i = 0; i < n; i++) itor = tb_find_all(iterator, (tb_pointer_t)data[800]); time = tb_mclock() - time; // item tb_long_t item = itor != tb_iterator_tail(iterator)? (tb_long_t)tb_iterator_item(iterator, itor) : 0; // time tb_trace_i("tb_find_int_all[%ld ?= %ld]: %lld ms", item, data[800], time); // free tb_free(data); } static tb_void_t tb_find_int_test_binary() { __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // make for (i = 0; i < n; i++) data[i] = i; // find tb_size_t itor = tb_iterator_tail(iterator); tb_hong_t time = tb_mclock(); for (i = 0; i < n; i++) itor = tb_binary_find_all(iterator, (tb_pointer_t)data[800]); time = tb_mclock() - time; // item tb_long_t item = itor != tb_iterator_tail(iterator)? (tb_long_t)tb_iterator_item(iterator, itor) : 0; // time tb_trace_i("tb_binary_find_int_all[%ld ?= %ld]: %lld ms", item, data[800], time); // free tb_free(data); } static tb_void_t tb_find_str_test() { __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_str(&array_iterator, data, n); // make tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%04lu", i); s[r] = '\0'; data[i] = tb_strdup(s); } // find tb_size_t itor = tb_iterator_tail(iterator); tb_hong_t time = tb_mclock(); for (i = 0; i < n; i++) itor = tb_find_all(iterator, (tb_pointer_t)data[800]); time = tb_mclock() - time; // item tb_char_t* item = itor != tb_iterator_tail(iterator)? (tb_char_t*)tb_iterator_item(iterator, itor) : 0; // time tb_trace_i("tb_find_str_all[%s ?= %s]: %lld ms", item, data[800], time); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); } static tb_void_t tb_find_str_test_binary() { __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_str(&array_iterator, data, n); // make tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%04lu", i); s[r] = '\0'; data[i] = tb_strdup(s); } // find tb_size_t itor = tb_iterator_tail(iterator); tb_hong_t time = tb_mclock(); for (i = 0; i < n; i++) itor = tb_binary_find_all(iterator, (tb_pointer_t)data[800]); time = tb_mclock() - time; // item tb_char_t* item = itor != tb_iterator_tail(iterator)? (tb_char_t*)tb_iterator_item(iterator, itor) : 0; // time tb_trace_i("tb_binary_find_str_all[%s ?= %s]: %lld ms", item, data[800], time); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_algorithm_find_main(tb_int_t argc, tb_char_t** argv) { // test tb_find_int_test(); tb_find_int_test_binary(); tb_find_str_test(); tb_find_str_test_binary(); return 0; } tbox-1.7.6/src/demo/algorithm/sort.c000066400000000000000000000310521467117505400173500ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * test */ static tb_void_t tb_sort_int_test_perf(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // make for (i = 0; i < n; i++) data[i] = tb_random_range(TB_MINS16, TB_MAXS16); // sort tb_hong_t time = tb_mclock(); tb_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_sort_int_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(data[i - 1] <= data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_perf_bubble(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // make for (i = 0; i < n; i++) data[i] = tb_random_range(TB_MINS16, TB_MAXS16); // sort tb_hong_t time = tb_mclock(); tb_bubble_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_bubble_sort_int_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(data[i - 1] <= data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_func_bubble() { // init __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 20; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // trace tb_trace_i(""); // put for (i = 0; i < n; i++) { data[i] = tb_random_range(TB_MINS16, TB_MAXS16); tb_trace_i("bubble_put: %ld", data[i]); } // sort tb_heap_sort_all(iterator, tb_null); // trace tb_trace_i(""); // pop for (i = 0; i < n; i++) tb_trace_i("bubble_pop: %ld", data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_perf_insert(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // make for (i = 0; i < n; i++) data[i] = tb_random_range(TB_MINS16, TB_MAXS16); // sort tb_hong_t time = tb_mclock(); tb_insert_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_insert_sort_int_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(data[i - 1] <= data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_func_insert() { // init __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 20; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // trace tb_trace_i(""); // put for (i = 0; i < n; i++) { data[i] = tb_random_range(TB_MINS16, TB_MAXS16); tb_trace_i("insert_put: %ld", data[i]); } // sort tb_heap_sort_all(iterator, tb_null); // trace tb_trace_i(""); // pop for (i = 0; i < n; i++) tb_trace_i("insert_pop: %ld", data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_perf_quick(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // make for (i = 0; i < n; i++) data[i] = tb_random_range(TB_MINS16, TB_MAXS16); // sort tb_hong_t time = tb_mclock(); tb_quick_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_quick_sort_int_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(data[i - 1] <= data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_func_quick() { // init __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 20; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // trace tb_trace_i(""); // put for (i = 0; i < n; i++) { data[i] = tb_random_range(TB_MINS16, TB_MAXS16); tb_trace_i("quick_put: %ld", data[i]); } // sort tb_heap_sort_all(iterator, tb_null); // trace tb_trace_i(""); // pop for (i = 0; i < n; i++) tb_trace_i("quick_pop: %ld", data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_perf_heap(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // make for (i = 0; i < n; i++) data[i] = tb_random_range(TB_MINS16, TB_MAXS16); // sort tb_hong_t time = tb_mclock(); tb_heap_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_heap_sort_int_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(data[i - 1] <= data[i]); // free tb_free(data); } static tb_void_t tb_sort_int_test_func_heap() { // init __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 20; // init data tb_long_t* data = (tb_long_t*)tb_nalloc0(n, sizeof(tb_long_t)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_long(&array_iterator, data, n); // trace tb_trace_i(""); // put for (i = 0; i < n; i++) { data[i] = tb_random_range(TB_MINS16, TB_MAXS16); tb_trace_i("heap_put: %ld", data[i]); } // sort tb_heap_sort_all(iterator, tb_null); // trace tb_trace_i(""); // pop for (i = 0; i < n; i++) tb_trace_i("heap_pop: %ld", data[i]); // free tb_free(data); } static tb_void_t tb_sort_str_test_perf(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_str(&array_iterator, data, n); // make tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%ld", tb_random_value()); s[r] = '\0'; data[i] = tb_strdup(s); } // sort tb_hong_t time = tb_mclock(); tb_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_sort_str_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(tb_strcmp(data[i - 1], data[i]) <= 0); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); } static tb_void_t tb_sort_str_test_perf_bubble(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_str(&array_iterator, data, n); // make tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%ld", tb_random_value()); s[r] = '\0'; data[i] = tb_strdup(s); } // sort tb_hong_t time = tb_mclock(); tb_bubble_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_bubble_sort_str_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(tb_strcmp(data[i - 1], data[i]) <= 0); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); } static tb_void_t tb_sort_str_test_perf_insert(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_str(&array_iterator, data, n); // make tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%ld", tb_random_value()); s[r] = '\0'; data[i] = tb_strdup(s); } // sort tb_hong_t time = tb_mclock(); tb_insert_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_insert_sort_str_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(tb_strcmp(data[i - 1], data[i]) <= 0); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); } static tb_void_t tb_sort_str_test_perf_quick(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_str(&array_iterator, data, n); // make tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%ld", tb_random_value()); s[r] = '\0'; data[i] = tb_strdup(s); } // sort tb_hong_t time = tb_mclock(); tb_quick_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_quick_sort_str_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(tb_strcmp(data[i - 1], data[i]) <= 0); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); } static tb_void_t tb_sort_str_test_perf_heap(tb_size_t n) { __tb_volatile__ tb_size_t i = 0; // init data tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*)); tb_assert_and_check_return(data); // init iterator tb_array_iterator_t array_iterator; tb_iterator_ref_t iterator = tb_array_iterator_init_str(&array_iterator, data, n); // make tb_char_t s[256] = {0}; for (i = 0; i < n; i++) { tb_long_t r = tb_snprintf(s, 256, "%ld", tb_random_value()); s[r] = '\0'; data[i] = tb_strdup(s); } // sort tb_hong_t time = tb_mclock(); tb_heap_sort_all(iterator, tb_null); time = tb_mclock() - time; // time tb_trace_i("tb_heap_sort_str_all: %lld ms", time); // check for (i = 1; i < n; i++) tb_assert_and_check_break(tb_strcmp(data[i - 1], data[i]) <= 0); // free data for (i = 0; i < n; i++) tb_free(data[i]); tb_free(data); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_algorithm_sort_main(tb_int_t argc, tb_char_t** argv) { // func tb_sort_int_test_func_heap(); tb_sort_int_test_func_quick(); tb_sort_int_test_func_bubble(); tb_sort_int_test_func_insert(); // perf tb_sort_int_test_perf(1000); tb_sort_int_test_perf_heap(1000); tb_sort_int_test_perf_quick(1000); tb_sort_int_test_perf_bubble(1000); tb_sort_int_test_perf_insert(1000); tb_sort_str_test_perf(1000); tb_sort_str_test_perf_heap(1000); tb_sort_str_test_perf_quick(1000); tb_sort_str_test_perf_bubble(1000); tb_sort_str_test_perf_insert(1000); return 0; } tbox-1.7.6/src/demo/container/000077500000000000000000000000001467117505400162105ustar00rootroot00000000000000tbox-1.7.6/src/demo/container/bloom_filter.c000066400000000000000000000254331467117505400210400ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ static tb_size_t g_func_indx = 0; static tb_element_t g_func_prev; /* ////////////////////////////////////////////////////////////////////////////////////// * test */ static tb_size_t tb_demo_test_hash_func(tb_element_ref_t element, tb_cpointer_t priv, tb_size_t mask, tb_size_t index) { return g_func_prev.hash(element, priv, mask, g_func_indx); } static tb_void_t tb_demo_test_cstr_h(tb_size_t index) { // the count tb_size_t count = 1000000; // save element g_func_indx = index; g_func_prev = tb_element_str(tb_true); // the element tb_element_t element = g_func_prev; element.hash = tb_demo_test_hash_func; // init filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_001, 1, count, element); if (filter) { // done tb_size_t i = 0; tb_size_t r = 0; tb_char_t s[256] = {0}; tb_hong_t t = tb_mclock(); for (i = 0; i < count; i++) { // the value tb_long_t value = tb_random(); // format it tb_snprintf(s, sizeof(s) - 1, "%ld", value); // set value to filter if (!tb_bloom_filter_set(filter, s)) { // repeat++ r++; } } t = tb_mclock() - t; // trace tb_trace_i("cstr: index: %lu, repeat: %lu, time: %lld ms", index, r, t); // exit filter tb_bloom_filter_exit(filter); } } static tb_void_t tb_demo_test_cstr_p() { // the count tb_size_t count = 10000000; // init filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_01, 3, count, tb_element_str(tb_true)); if (filter) { // done tb_size_t i = 0; tb_size_t r = 0; tb_char_t s[256] = {0}; for (i = 0; i < count; i++) { // the value tb_long_t value = tb_random(); // format it tb_snprintf(s, sizeof(s) - 1, "%ld", value); // set value to filter if (!tb_bloom_filter_set(filter, s)) { // repeat++ r++; } } // trace #ifdef TB_CONFIG_TYPE_HAVE_FLOAT tb_trace_i("cstr: count: %lu, repeat: %lu, repeat_p ~= p: %lf", count, r, (tb_double_t)r / count); #else tb_trace_i("cstr: count: %lu, repeat: %lu", count, r); #endif // exit filter tb_bloom_filter_exit(filter); } } static tb_void_t tb_demo_test_uint8_h(tb_size_t index) { // the count tb_size_t count = TB_MAXU8; // save element g_func_indx = index; g_func_prev = tb_element_uint8(); // the element tb_element_t element = g_func_prev; element.hash = tb_demo_test_hash_func; // init filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_001, 1, count, element); if (filter) { // done tb_size_t i = 0; tb_size_t r = 0; tb_hong_t t = tb_mclock(); for (i = 0; i < count; i++) { // the value tb_long_t value = tb_random_range(0, TB_MAXU8); // set value to filter if (!tb_bloom_filter_set(filter, (tb_cpointer_t)value)) { // repeat++ r++; } } t = tb_mclock() - t; // trace tb_trace_i("uint8: index: %lu, repeat: %lu, time: %lld ms", index, r, t); // exit filter tb_bloom_filter_exit(filter); } } static tb_void_t tb_demo_test_uint16_h(tb_size_t index) { // the count tb_size_t count = TB_MAXU16; // save element g_func_indx = index; g_func_prev = tb_element_uint16(); // the element tb_element_t element = g_func_prev; element.hash = tb_demo_test_hash_func; // init filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_001, 1, count, element); if (filter) { // done tb_size_t i = 0; tb_size_t r = 0; tb_hong_t t = tb_mclock(); for (i = 0; i < count; i++) { // the value tb_long_t value = tb_random_range(0, TB_MAXU16); // set value to filter if (!tb_bloom_filter_set(filter, (tb_cpointer_t)value)) { // repeat++ r++; } } t = tb_mclock() - t; // trace tb_trace_i("uint16: index: %lu, repeat: %lu, time: %lld ms", index, r, t); // exit filter tb_bloom_filter_exit(filter); } } static tb_void_t tb_demo_test_uint32_h(tb_size_t index) { // the count tb_size_t count = 1000000; // save element g_func_indx = index; g_func_prev = tb_element_uint32(); // the element tb_element_t element = g_func_prev; element.hash = tb_demo_test_hash_func; // init filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_001, 1, count, element); if (filter) { // done tb_size_t i = 0; tb_size_t r = 0; tb_hong_t t = tb_mclock(); for (i = 0; i < count; i++) { // the value tb_long_t value = tb_random_value(); // set value to filter if (!tb_bloom_filter_set(filter, (tb_cpointer_t)value)) { // repeat++ r++; } } t = tb_mclock() - t; // trace tb_trace_i("uint32: index: %lu, repeat: %lu, time: %lld ms", index, r, t); // exit filter tb_bloom_filter_exit(filter); } } static tb_void_t tb_demo_test_long_h(tb_size_t index) { // the count tb_size_t count = 1000000; // save element g_func_indx = index; g_func_prev = tb_element_long(); // the element tb_element_t element = g_func_prev; element.hash = tb_demo_test_hash_func; // init filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_001, 1, count, element); if (filter) { // done tb_size_t i = 0; tb_size_t r = 0; tb_hong_t t = tb_mclock(); for (i = 0; i < count; i++) { // the value tb_long_t value = tb_random(); // set value to filter if (!tb_bloom_filter_set(filter, (tb_cpointer_t)value)) { // repeat++ r++; } } t = tb_mclock() - t; // trace tb_trace_i("long: index: %lu, repeat: %lu, time: %lld ms", index, r, t); // exit filter tb_bloom_filter_exit(filter); } } static tb_void_t tb_demo_test_long_p() { // the count tb_size_t count = 10000000; // init filter tb_bloom_filter_ref_t filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_01, 3, count, tb_element_long()); if (filter) { // done tb_size_t i = 0; tb_size_t r = 0; for (i = 0; i < count; i++) { // the value tb_long_t value = tb_random(); // set value to filter if (!tb_bloom_filter_set(filter, (tb_cpointer_t)value)) { // repeat++ r++; } } // trace #ifdef TB_CONFIG_TYPE_HAVE_FLOAT tb_trace_i("long: count: %lu, repeat: %lu, repeat_p ~= p: %lf", count, r, (tb_double_t)r / count); #else tb_trace_i("long: count: %lu, repeat: %lu", count, r); #endif // exit filter tb_bloom_filter_exit(filter); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_bloom_filter_main(tb_int_t argc, tb_char_t** argv) { tb_trace_i("==========================================================="); tb_demo_test_uint8_h(0); tb_demo_test_uint8_h(1); tb_demo_test_uint8_h(2); tb_demo_test_uint8_h(3); tb_demo_test_uint8_h(4); tb_demo_test_uint8_h(5); tb_demo_test_uint8_h(6); tb_demo_test_uint8_h(7); tb_demo_test_uint8_h(8); tb_demo_test_uint8_h(9); tb_demo_test_uint8_h(10); tb_demo_test_uint8_h(11); tb_demo_test_uint8_h(12); tb_demo_test_uint8_h(13); tb_demo_test_uint8_h(14); tb_demo_test_uint8_h(15); tb_trace_i("==========================================================="); tb_demo_test_uint16_h(0); tb_demo_test_uint16_h(1); tb_demo_test_uint16_h(2); tb_demo_test_uint16_h(3); tb_demo_test_uint16_h(4); tb_demo_test_uint16_h(5); tb_demo_test_uint16_h(6); tb_demo_test_uint16_h(7); tb_demo_test_uint16_h(8); tb_demo_test_uint16_h(9); tb_demo_test_uint16_h(10); tb_demo_test_uint16_h(11); tb_demo_test_uint16_h(12); tb_demo_test_uint16_h(13); tb_demo_test_uint16_h(14); tb_demo_test_uint16_h(15); tb_trace_i("==========================================================="); tb_demo_test_uint32_h(0); tb_demo_test_uint32_h(1); tb_demo_test_uint32_h(2); tb_demo_test_uint32_h(3); tb_demo_test_uint32_h(4); tb_demo_test_uint32_h(5); tb_demo_test_uint32_h(6); tb_demo_test_uint32_h(7); tb_demo_test_uint32_h(8); tb_demo_test_uint32_h(9); tb_demo_test_uint32_h(10); tb_demo_test_uint32_h(11); tb_demo_test_uint32_h(12); tb_demo_test_uint32_h(13); tb_demo_test_uint32_h(14); tb_demo_test_uint32_h(15); tb_trace_i("==========================================================="); tb_demo_test_long_h(0); tb_demo_test_long_h(1); tb_demo_test_long_h(2); tb_demo_test_long_h(3); tb_demo_test_long_h(4); tb_demo_test_long_h(5); tb_demo_test_long_h(6); tb_demo_test_long_h(7); tb_demo_test_long_h(8); tb_demo_test_long_h(9); tb_demo_test_long_h(10); tb_demo_test_long_h(11); tb_demo_test_long_h(12); tb_demo_test_long_h(13); tb_demo_test_long_h(14); tb_demo_test_long_h(15); tb_trace_i("==========================================================="); tb_demo_test_cstr_h(0); tb_demo_test_cstr_h(1); tb_demo_test_cstr_h(2); tb_demo_test_cstr_h(3); tb_demo_test_cstr_h(4); tb_demo_test_cstr_h(5); tb_demo_test_cstr_h(6); tb_demo_test_cstr_h(7); tb_demo_test_cstr_h(8); tb_demo_test_cstr_h(9); tb_demo_test_cstr_h(10); tb_demo_test_cstr_h(11); tb_demo_test_cstr_h(12); // tb_demo_test_cstr_h(13); // tb_demo_test_cstr_h(14); // tb_demo_test_cstr_h(15); tb_trace_i("==========================================================="); tb_demo_test_long_p(); tb_demo_test_cstr_p(); return 0; } tbox-1.7.6/src/demo/container/circle_queue.c000066400000000000000000000212661467117505400210300ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_circle_queue_put_and_pop_test() { // init tb_circle_queue_ref_t queue = tb_circle_queue_init(10, tb_element_long()); tb_assert_and_check_return(queue); // make queue tb_circle_queue_put(queue, (tb_pointer_t)0); tb_circle_queue_put(queue, (tb_pointer_t)1); tb_circle_queue_put(queue, (tb_pointer_t)2); tb_circle_queue_put(queue, (tb_pointer_t)3); tb_circle_queue_put(queue, (tb_pointer_t)4); tb_circle_queue_put(queue, (tb_pointer_t)5); tb_circle_queue_put(queue, (tb_pointer_t)6); tb_circle_queue_put(queue, (tb_pointer_t)7); tb_circle_queue_put(queue, (tb_pointer_t)8); tb_circle_queue_put(queue, (tb_pointer_t)9); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) { tb_circle_queue_pop(queue); tb_circle_queue_put(queue, (tb_pointer_t)0xf); } t = tb_mclock() - t; // trace tb_trace_i("tb_circle_queue_put_and_pop(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_circle_queue_size(queue), tb_circle_queue_maxn(queue)); // check tb_assert(tb_circle_queue_size(queue) == 10); tb_assert(tb_circle_queue_head(queue) == (tb_pointer_t)0xf); tb_assert(tb_circle_queue_last(queue) == (tb_pointer_t)0xf); // clear it tb_circle_queue_clear(queue); tb_assert(!tb_circle_queue_size(queue)); // exit tb_circle_queue_exit(queue); } static tb_void_t tb_circle_queue_iterator_next_test() { // init tb_size_t n = 1000000; tb_circle_queue_ref_t queue = tb_circle_queue_init(n, tb_element_long()); tb_assert_and_check_return(queue); // make queue while (n--) tb_circle_queue_put(queue, (tb_pointer_t)0xf); // done tb_hong_t t = tb_mclock(); tb_for_all (tb_char_t*, item, queue) tb_used(item); t = tb_mclock() - t; // trace tb_trace_i("tb_circle_queue_iterator_next(%lu): %lld ms, size: %lu, maxn: %lu", 1000000, t, tb_circle_queue_size(queue), tb_circle_queue_maxn(queue)); // exit tb_circle_queue_exit(queue); } static tb_void_t tb_circle_queue_int_dump(tb_circle_queue_ref_t queue) { tb_trace_i("tb_int_t size: %lu, maxn: %lu", tb_circle_queue_size(queue), tb_circle_queue_maxn(queue)); tb_for_all (tb_char_t*, item, queue) { tb_trace_i("tb_int_t at[%lu]: %u", item_itor, item); } } static tb_void_t tb_circle_queue_int_test() { tb_circle_queue_ref_t queue = tb_circle_queue_init(10, tb_element_long()); tb_assert_and_check_return(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_circle_queue_put(queue, (tb_pointer_t)0); tb_circle_queue_put(queue, (tb_pointer_t)1); tb_circle_queue_put(queue, (tb_pointer_t)2); tb_circle_queue_put(queue, (tb_pointer_t)3); tb_circle_queue_put(queue, (tb_pointer_t)4); tb_circle_queue_put(queue, (tb_pointer_t)5); tb_circle_queue_put(queue, (tb_pointer_t)6); tb_circle_queue_put(queue, (tb_pointer_t)7); tb_circle_queue_put(queue, (tb_pointer_t)8); tb_circle_queue_put(queue, (tb_pointer_t)9); tb_circle_queue_int_dump(queue); tb_trace_i("============================================================="); tb_trace_i("pop:"); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_int_dump(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_circle_queue_put(queue, (tb_pointer_t)0); tb_circle_queue_put(queue, (tb_pointer_t)1); tb_circle_queue_put(queue, (tb_pointer_t)2); tb_circle_queue_put(queue, (tb_pointer_t)3); tb_circle_queue_put(queue, (tb_pointer_t)4); tb_circle_queue_int_dump(queue); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_circle_queue_clear(queue); tb_circle_queue_int_dump(queue); tb_circle_queue_exit(queue); } static tb_void_t tb_circle_queue_str_dump(tb_circle_queue_ref_t queue) { tb_trace_i("str size: %lu, maxn: %lu", tb_circle_queue_size(queue), tb_circle_queue_maxn(queue)); tb_for_all (tb_char_t*, item, queue) { tb_trace_i("str at[%lu]: %s", item_itor, item); } } static tb_void_t tb_circle_queue_str_test() { tb_circle_queue_ref_t queue = tb_circle_queue_init(10, tb_element_str(tb_true)); tb_assert_and_check_return(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_circle_queue_put(queue, "0000000000"); tb_circle_queue_put(queue, "1111111111"); tb_circle_queue_put(queue, "2222222222"); tb_circle_queue_put(queue, "3333333333"); tb_circle_queue_put(queue, "4444444444"); tb_circle_queue_put(queue, "5555555555"); tb_circle_queue_put(queue, "6666666666"); tb_circle_queue_put(queue, "7777777777"); tb_circle_queue_put(queue, "8888888888"); tb_circle_queue_put(queue, "9999999999"); tb_circle_queue_str_dump(queue); tb_trace_i("============================================================="); tb_trace_i("pop:"); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_str_dump(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_circle_queue_put(queue, "0000000000"); tb_circle_queue_put(queue, "1111111111"); tb_circle_queue_put(queue, "2222222222"); tb_circle_queue_put(queue, "3333333333"); tb_circle_queue_put(queue, "4444444444"); tb_circle_queue_str_dump(queue); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_circle_queue_clear(queue); tb_circle_queue_str_dump(queue); tb_circle_queue_exit(queue); } static tb_void_t tb_circle_queue_mem_free(tb_element_ref_t element, tb_pointer_t buff) { tb_trace_i("ifm free: %s, priv: %s", buff, element->priv); } static tb_void_t tb_circle_queue_mem_dump(tb_circle_queue_ref_t queue) { tb_trace_i("ifm size: %lu, maxn: %lu", tb_circle_queue_size(queue), tb_circle_queue_maxn(queue)); tb_for_all (tb_char_t*, item, queue) { tb_trace_i("ifm at[%lu]: %s", item_itor, item); } } static tb_void_t tb_circle_queue_mem_test() { tb_circle_queue_ref_t queue = tb_circle_queue_init(10, tb_element_mem(11, tb_circle_queue_mem_free, "ifm")); tb_assert_and_check_return(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_circle_queue_put(queue, "0000000000"); tb_circle_queue_put(queue, "1111111111"); tb_circle_queue_put(queue, "2222222222"); tb_circle_queue_put(queue, "3333333333"); tb_circle_queue_put(queue, "4444444444"); tb_circle_queue_put(queue, "5555555555"); tb_circle_queue_put(queue, "6666666666"); tb_circle_queue_put(queue, "7777777777"); tb_circle_queue_put(queue, "8888888888"); tb_circle_queue_put(queue, "9999999999"); tb_circle_queue_mem_dump(queue); tb_trace_i("============================================================="); tb_trace_i("pop:"); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_pop(queue); tb_circle_queue_mem_dump(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_circle_queue_put(queue, "0000000000"); tb_circle_queue_put(queue, "1111111111"); tb_circle_queue_put(queue, "2222222222"); tb_circle_queue_put(queue, "3333333333"); tb_circle_queue_put(queue, "4444444444"); tb_circle_queue_mem_dump(queue); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_circle_queue_clear(queue); tb_circle_queue_mem_dump(queue); tb_circle_queue_exit(queue); } static tb_void_t tb_circle_queue_perf_test() { tb_circle_queue_put_and_pop_test(); tb_circle_queue_iterator_next_test(); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_circle_queue_main(tb_int_t argc, tb_char_t** argv) { tb_circle_queue_int_test(); tb_circle_queue_str_test(); tb_circle_queue_mem_test(); tb_circle_queue_perf_test(); return 0; } tbox-1.7.6/src/demo/container/hash_map.c000066400000000000000000000541131467117505400201400ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #ifdef __tb_debug__ # define tb_hash_map_test_dump(h) tb_hash_map_dump(h) #else # define tb_hash_map_test_dump(h) #endif #define tb_hash_map_test_get_s2i(h, s) do {tb_assert(tb_strlen((tb_char_t*)s) == (tb_size_t)tb_hash_map_get(h, (tb_char_t*)(s))); } while (0); #define tb_hash_map_test_insert_s2i(h, s) do {tb_size_t n = tb_strlen((tb_char_t*)(s)); tb_hash_map_insert(h, (tb_char_t*)(s), (tb_pointer_t)n); } while (0); #define tb_hash_map_test_remove_s2i(h, s) do {tb_hash_map_remove(h, s); tb_assert(!tb_hash_map_get(h, s)); } while (0); #define tb_hash_map_test_get_i2s(h, i) do {tb_char_t s[256] = {0}; tb_snprintf(s, 256, "%u", i); tb_assert(!tb_strcmp(s, (tb_char_t const*)tb_hash_map_get(h, (tb_pointer_t)i))); } while (0); #define tb_hash_map_test_insert_i2s(h, i) do {tb_char_t s[256] = {0}; tb_snprintf(s, 256, "%u", i); tb_hash_map_insert(h, (tb_pointer_t)i, s); } while (0); #define tb_hash_map_test_remove_i2s(h, i) do {tb_hash_map_remove(h, (tb_pointer_t)i); tb_assert(!tb_hash_map_get(h, (tb_pointer_t)i)); } while (0); #define tb_hash_map_test_get_m2m(h, i) do {tb_memset_u32(item, i, step >> 2); tb_assert(!tb_memcmp(item, tb_hash_map_get(h, item), step)); } while (0); #define tb_hash_map_test_insert_m2m(h, i) do {tb_memset_u32(item, i, step >> 2); tb_hash_map_insert(h, item, item); } while (0); #define tb_hash_map_test_remove_m2m(h, i) do {tb_memset_u32(item, i, step >> 2); tb_hash_map_remove(h, item); tb_assert(!tb_hash_map_get(h, item)); } while (0); #define tb_hash_map_test_get_i2i(h, i) do {tb_assert(i == (tb_size_t)tb_hash_map_get(h, (tb_pointer_t)i)); } while (0); #define tb_hash_map_test_insert_i2i(h, i) do {tb_hash_map_insert(h, (tb_pointer_t)i, (tb_pointer_t)i); } while (0); #define tb_hash_map_test_remove_i2i(h, i) do {tb_hash_map_remove(h, (tb_pointer_t)i); tb_assert(!tb_hash_map_get(h, (tb_pointer_t)i)); } while (0); #define tb_hash_map_test_get_i2t(h, i) do {tb_assert(tb_hash_map_get(h, (tb_pointer_t)i)); } while (0); #define tb_hash_map_test_insert_i2t(h, i) do {tb_hash_map_insert(h, (tb_pointer_t)i, (tb_pointer_t)(tb_size_t)tb_true); } while (0); #define tb_hash_map_test_remove_i2t(h, i) do {tb_hash_map_remove(h, (tb_pointer_t)i); tb_assert(!tb_hash_map_get(h, (tb_pointer_t)i)); } while (0); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_hash_map_test_s2i_func() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(8, tb_element_str(tb_true), tb_element_long()); tb_assert_and_check_return(hash); // set tb_hash_map_test_insert_s2i(hash, ""); tb_hash_map_test_insert_s2i(hash, "0"); tb_hash_map_test_insert_s2i(hash, "01"); tb_hash_map_test_insert_s2i(hash, "012"); tb_hash_map_test_insert_s2i(hash, "0123"); tb_hash_map_test_insert_s2i(hash, "01234"); tb_hash_map_test_insert_s2i(hash, "012345"); tb_hash_map_test_insert_s2i(hash, "0123456"); tb_hash_map_test_insert_s2i(hash, "01234567"); tb_hash_map_test_insert_s2i(hash, "012345678"); tb_hash_map_test_insert_s2i(hash, "0123456789"); tb_hash_map_test_insert_s2i(hash, "9876543210"); tb_hash_map_test_insert_s2i(hash, "876543210"); tb_hash_map_test_insert_s2i(hash, "76543210"); tb_hash_map_test_insert_s2i(hash, "6543210"); tb_hash_map_test_insert_s2i(hash, "543210"); tb_hash_map_test_insert_s2i(hash, "43210"); tb_hash_map_test_insert_s2i(hash, "3210"); tb_hash_map_test_insert_s2i(hash, "210"); tb_hash_map_test_insert_s2i(hash, "10"); tb_hash_map_test_insert_s2i(hash, "0"); tb_hash_map_test_insert_s2i(hash, ""); tb_hash_map_test_dump(hash); // get tb_hash_map_test_get_s2i(hash, ""); tb_hash_map_test_get_s2i(hash, "01"); tb_hash_map_test_get_s2i(hash, "012"); tb_hash_map_test_get_s2i(hash, "0123"); tb_hash_map_test_get_s2i(hash, "01234"); tb_hash_map_test_get_s2i(hash, "012345"); tb_hash_map_test_get_s2i(hash, "0123456"); tb_hash_map_test_get_s2i(hash, "01234567"); tb_hash_map_test_get_s2i(hash, "012345678"); tb_hash_map_test_get_s2i(hash, "0123456789"); tb_hash_map_test_get_s2i(hash, "9876543210"); tb_hash_map_test_get_s2i(hash, "876543210"); tb_hash_map_test_get_s2i(hash, "76543210"); tb_hash_map_test_get_s2i(hash, "6543210"); tb_hash_map_test_get_s2i(hash, "543210"); tb_hash_map_test_get_s2i(hash, "43210"); tb_hash_map_test_get_s2i(hash, "3210"); tb_hash_map_test_get_s2i(hash, "210"); tb_hash_map_test_get_s2i(hash, "10"); tb_hash_map_test_get_s2i(hash, "0"); tb_hash_map_test_get_s2i(hash, ""); // del tb_hash_map_test_remove_s2i(hash, ""); tb_hash_map_test_remove_s2i(hash, "01"); tb_hash_map_test_remove_s2i(hash, "012"); tb_hash_map_test_remove_s2i(hash, "0123"); tb_hash_map_test_remove_s2i(hash, "01234"); tb_hash_map_test_remove_s2i(hash, "012345"); tb_hash_map_test_remove_s2i(hash, "0123456"); tb_hash_map_test_remove_s2i(hash, "01234567"); tb_hash_map_test_remove_s2i(hash, "012345678"); tb_hash_map_test_remove_s2i(hash, "0123456789"); tb_hash_map_test_remove_s2i(hash, "0123456789"); tb_hash_map_test_dump(hash); // clear tb_hash_map_clear(hash); tb_hash_map_test_dump(hash); tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_s2i_perf() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(0, tb_element_str(tb_true), tb_element_long()); tb_assert_and_check_return(hash); // performance tb_char_t s[256] = {0}; __tb_volatile__ tb_size_t n = 100000; tb_hong_t t = tb_mclock(); while (n--) { tb_long_t r = tb_snprintf(s, sizeof(s) - 1, "%ld", tb_random_value()); s[r] = '\0'; tb_hash_map_test_insert_s2i(hash, s); tb_hash_map_test_get_s2i(hash, s); } t = tb_mclock() - t; tb_trace_i("s2i: time: %lld", t); tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_i2s_func() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(8, tb_element_long(), tb_element_str(tb_true)); tb_assert_and_check_return(hash); // set tb_hash_map_test_insert_i2s(hash, 0); tb_hash_map_test_insert_i2s(hash, 1); tb_hash_map_test_insert_i2s(hash, 12); tb_hash_map_test_insert_i2s(hash, 123); tb_hash_map_test_insert_i2s(hash, 1234); tb_hash_map_test_insert_i2s(hash, 12345); tb_hash_map_test_insert_i2s(hash, 123456); tb_hash_map_test_insert_i2s(hash, 1234567); tb_hash_map_test_insert_i2s(hash, 12345678); tb_hash_map_test_insert_i2s(hash, 123456789); tb_hash_map_test_insert_i2s(hash, 876543210); tb_hash_map_test_insert_i2s(hash, 76543210); tb_hash_map_test_insert_i2s(hash, 6543210); tb_hash_map_test_insert_i2s(hash, 543210); tb_hash_map_test_insert_i2s(hash, 43210); tb_hash_map_test_insert_i2s(hash, 3210); tb_hash_map_test_insert_i2s(hash, 210); tb_hash_map_test_insert_i2s(hash, 10); tb_hash_map_test_insert_i2s(hash, 0); tb_hash_map_test_dump(hash); // get tb_hash_map_test_get_i2s(hash, 0); tb_hash_map_test_get_i2s(hash, 1); tb_hash_map_test_get_i2s(hash, 12); tb_hash_map_test_get_i2s(hash, 123); tb_hash_map_test_get_i2s(hash, 1234); tb_hash_map_test_get_i2s(hash, 12345); tb_hash_map_test_get_i2s(hash, 123456); tb_hash_map_test_get_i2s(hash, 1234567); tb_hash_map_test_get_i2s(hash, 12345678); tb_hash_map_test_get_i2s(hash, 123456789); tb_hash_map_test_get_i2s(hash, 876543210); tb_hash_map_test_get_i2s(hash, 76543210); tb_hash_map_test_get_i2s(hash, 6543210); tb_hash_map_test_get_i2s(hash, 543210); tb_hash_map_test_get_i2s(hash, 43210); tb_hash_map_test_get_i2s(hash, 3210); tb_hash_map_test_get_i2s(hash, 210); tb_hash_map_test_get_i2s(hash, 10); tb_hash_map_test_get_i2s(hash, 0); // del tb_hash_map_test_remove_i2s(hash, 0); tb_hash_map_test_remove_i2s(hash, 1); tb_hash_map_test_remove_i2s(hash, 12); tb_hash_map_test_remove_i2s(hash, 123); tb_hash_map_test_remove_i2s(hash, 1234); tb_hash_map_test_remove_i2s(hash, 12345); tb_hash_map_test_remove_i2s(hash, 123456); tb_hash_map_test_remove_i2s(hash, 1234567); tb_hash_map_test_remove_i2s(hash, 12345678); tb_hash_map_test_remove_i2s(hash, 123456789); tb_hash_map_test_remove_i2s(hash, 123456789); tb_hash_map_test_dump(hash); // clear tb_hash_map_clear(hash); tb_hash_map_test_dump(hash); // exit tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_i2s_perf() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(0, tb_element_long(), tb_element_str(tb_true)); tb_assert_and_check_return(hash); // performance __tb_volatile__ tb_size_t n = 100000; tb_hong_t t = tb_mclock(); while (n--) { tb_size_t i = tb_random_value(); tb_hash_map_test_insert_i2s(hash, i); tb_hash_map_test_get_i2s(hash, i); } t = tb_mclock() - t; tb_trace_i("i2s: time: %lld", t); tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_m2m_func() { // init hash tb_size_t const step = 256; tb_byte_t item[step]; tb_hash_map_ref_t hash = tb_hash_map_init(8, tb_element_mem(step, tb_null, tb_null), tb_element_mem(step, tb_null, tb_null)); tb_assert_and_check_return(hash); // set tb_hash_map_test_insert_m2m(hash, 0); tb_hash_map_test_insert_m2m(hash, 1); tb_hash_map_test_insert_m2m(hash, 2); tb_hash_map_test_insert_m2m(hash, 3); tb_hash_map_test_insert_m2m(hash, 4); tb_hash_map_test_insert_m2m(hash, 5); tb_hash_map_test_insert_m2m(hash, 6); tb_hash_map_test_insert_m2m(hash, 7); tb_hash_map_test_insert_m2m(hash, 8); tb_hash_map_test_insert_m2m(hash, 9); tb_hash_map_test_insert_m2m(hash, 10); tb_hash_map_test_insert_m2m(hash, 11); tb_hash_map_test_insert_m2m(hash, 12); tb_hash_map_test_insert_m2m(hash, 13); tb_hash_map_test_insert_m2m(hash, 14); tb_hash_map_test_insert_m2m(hash, 15); tb_hash_map_test_insert_m2m(hash, 16); tb_hash_map_test_insert_m2m(hash, 17); tb_hash_map_test_insert_m2m(hash, 18); tb_hash_map_test_insert_m2m(hash, 19); tb_hash_map_test_insert_m2m(hash, 20); tb_hash_map_test_insert_m2m(hash, 21); tb_hash_map_test_insert_m2m(hash, 22); tb_hash_map_test_insert_m2m(hash, 23); tb_hash_map_test_insert_m2m(hash, 24); tb_hash_map_test_insert_m2m(hash, 25); tb_hash_map_test_insert_m2m(hash, 26); tb_hash_map_test_insert_m2m(hash, 27); tb_hash_map_test_insert_m2m(hash, 28); tb_hash_map_test_insert_m2m(hash, 29); tb_hash_map_test_insert_m2m(hash, 30); tb_hash_map_test_insert_m2m(hash, 31); tb_hash_map_test_insert_m2m(hash, 32); tb_hash_map_test_dump(hash); // get tb_hash_map_test_get_m2m(hash, 0); tb_hash_map_test_get_m2m(hash, 1); tb_hash_map_test_get_m2m(hash, 2); tb_hash_map_test_get_m2m(hash, 3); tb_hash_map_test_get_m2m(hash, 4); tb_hash_map_test_get_m2m(hash, 5); tb_hash_map_test_get_m2m(hash, 6); tb_hash_map_test_get_m2m(hash, 7); tb_hash_map_test_get_m2m(hash, 8); tb_hash_map_test_get_m2m(hash, 9); tb_hash_map_test_get_m2m(hash, 10); tb_hash_map_test_get_m2m(hash, 11); tb_hash_map_test_get_m2m(hash, 12); tb_hash_map_test_get_m2m(hash, 13); tb_hash_map_test_get_m2m(hash, 14); tb_hash_map_test_get_m2m(hash, 15); tb_hash_map_test_get_m2m(hash, 16); tb_hash_map_test_get_m2m(hash, 17); tb_hash_map_test_get_m2m(hash, 18); tb_hash_map_test_get_m2m(hash, 19); tb_hash_map_test_get_m2m(hash, 20); tb_hash_map_test_get_m2m(hash, 21); tb_hash_map_test_get_m2m(hash, 22); tb_hash_map_test_get_m2m(hash, 23); tb_hash_map_test_get_m2m(hash, 24); tb_hash_map_test_get_m2m(hash, 25); tb_hash_map_test_get_m2m(hash, 26); tb_hash_map_test_get_m2m(hash, 27); tb_hash_map_test_get_m2m(hash, 28); tb_hash_map_test_get_m2m(hash, 29); tb_hash_map_test_get_m2m(hash, 30); tb_hash_map_test_get_m2m(hash, 31); tb_hash_map_test_get_m2m(hash, 32); // del tb_hash_map_test_remove_m2m(hash, 10); tb_hash_map_test_remove_m2m(hash, 11); tb_hash_map_test_remove_m2m(hash, 12); tb_hash_map_test_remove_m2m(hash, 13); tb_hash_map_test_remove_m2m(hash, 14); tb_hash_map_test_remove_m2m(hash, 15); tb_hash_map_test_remove_m2m(hash, 16); tb_hash_map_test_remove_m2m(hash, 17); tb_hash_map_test_remove_m2m(hash, 18); tb_hash_map_test_remove_m2m(hash, 19); tb_hash_map_test_remove_m2m(hash, 20); tb_hash_map_test_remove_m2m(hash, 21); tb_hash_map_test_remove_m2m(hash, 22); tb_hash_map_test_remove_m2m(hash, 23); tb_hash_map_test_remove_m2m(hash, 24); tb_hash_map_test_remove_m2m(hash, 25); tb_hash_map_test_remove_m2m(hash, 26); tb_hash_map_test_remove_m2m(hash, 27); tb_hash_map_test_remove_m2m(hash, 28); tb_hash_map_test_remove_m2m(hash, 29); tb_hash_map_test_remove_m2m(hash, 30); tb_hash_map_test_remove_m2m(hash, 31); tb_hash_map_test_remove_m2m(hash, 32); tb_hash_map_test_dump(hash); // clear tb_hash_map_clear(hash); tb_hash_map_test_dump(hash); tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_m2m_perf() { // init hash: mem => mem tb_size_t const step = 12; tb_byte_t item[step]; tb_hash_map_ref_t hash = tb_hash_map_init(0, tb_element_mem(step, tb_null, tb_null), tb_element_mem(step, tb_null, tb_null)); tb_assert_and_check_return(hash); // performance __tb_volatile__ tb_size_t n = 100000; tb_hong_t t = tb_mclock(); while (n--) { tb_uint32_t i = (tb_uint32_t)tb_random_value(); tb_hash_map_test_insert_m2m(hash, i); tb_hash_map_test_get_m2m(hash, i); } t = tb_mclock() - t; tb_trace_i("m2m: time: %lld", t); tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_i2i_func() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(8, tb_element_long(), tb_element_long()); tb_assert_and_check_return(hash); // set tb_hash_map_test_insert_i2i(hash, 0); tb_hash_map_test_insert_i2i(hash, 1); tb_hash_map_test_insert_i2i(hash, 12); tb_hash_map_test_insert_i2i(hash, 123); tb_hash_map_test_insert_i2i(hash, 1234); tb_hash_map_test_insert_i2i(hash, 12345); tb_hash_map_test_insert_i2i(hash, 123456); tb_hash_map_test_insert_i2i(hash, 1234567); tb_hash_map_test_insert_i2i(hash, 12345678); tb_hash_map_test_insert_i2i(hash, 123456789); tb_hash_map_test_insert_i2i(hash, 876543210); tb_hash_map_test_insert_i2i(hash, 76543210); tb_hash_map_test_insert_i2i(hash, 6543210); tb_hash_map_test_insert_i2i(hash, 543210); tb_hash_map_test_insert_i2i(hash, 43210); tb_hash_map_test_insert_i2i(hash, 3210); tb_hash_map_test_insert_i2i(hash, 210); tb_hash_map_test_insert_i2i(hash, 10); tb_hash_map_test_insert_i2i(hash, 0); tb_hash_map_test_dump(hash); // get tb_hash_map_test_get_i2i(hash, 0); tb_hash_map_test_get_i2i(hash, 1); tb_hash_map_test_get_i2i(hash, 12); tb_hash_map_test_get_i2i(hash, 123); tb_hash_map_test_get_i2i(hash, 1234); tb_hash_map_test_get_i2i(hash, 12345); tb_hash_map_test_get_i2i(hash, 123456); tb_hash_map_test_get_i2i(hash, 1234567); tb_hash_map_test_get_i2i(hash, 12345678); tb_hash_map_test_get_i2i(hash, 123456789); tb_hash_map_test_get_i2i(hash, 876543210); tb_hash_map_test_get_i2i(hash, 76543210); tb_hash_map_test_get_i2i(hash, 6543210); tb_hash_map_test_get_i2i(hash, 543210); tb_hash_map_test_get_i2i(hash, 43210); tb_hash_map_test_get_i2i(hash, 3210); tb_hash_map_test_get_i2i(hash, 210); tb_hash_map_test_get_i2i(hash, 10); tb_hash_map_test_get_i2i(hash, 0); // del tb_hash_map_test_remove_i2i(hash, 0); tb_hash_map_test_remove_i2i(hash, 1); tb_hash_map_test_remove_i2i(hash, 12); tb_hash_map_test_remove_i2i(hash, 123); tb_hash_map_test_remove_i2i(hash, 1234); tb_hash_map_test_remove_i2i(hash, 12345); tb_hash_map_test_remove_i2i(hash, 123456); tb_hash_map_test_remove_i2i(hash, 1234567); tb_hash_map_test_remove_i2i(hash, 12345678); tb_hash_map_test_remove_i2i(hash, 123456789); tb_hash_map_test_remove_i2i(hash, 123456789); tb_hash_map_test_dump(hash); // clear tb_hash_map_clear(hash); tb_hash_map_test_dump(hash); tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_i2i_perf() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(0, tb_element_long(), tb_element_long()); tb_assert_and_check_return(hash); // performance __tb_volatile__ tb_size_t n = 100000; tb_hong_t t = tb_mclock(); while (n--) { tb_size_t i = tb_random_value(); tb_hash_map_test_insert_i2i(hash, i); tb_hash_map_test_get_i2i(hash, i); } t = tb_mclock() - t; tb_trace_i("i2i: time: %lld", t); tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_i2t_func() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(8, tb_element_long(), tb_element_true()); tb_assert_and_check_return(hash); // set tb_hash_map_test_insert_i2t(hash, 0); tb_hash_map_test_insert_i2t(hash, 1); tb_hash_map_test_insert_i2t(hash, 12); tb_hash_map_test_insert_i2t(hash, 123); tb_hash_map_test_insert_i2t(hash, 1234); tb_hash_map_test_insert_i2t(hash, 12345); tb_hash_map_test_insert_i2t(hash, 123456); tb_hash_map_test_insert_i2t(hash, 1234567); tb_hash_map_test_insert_i2t(hash, 12345678); tb_hash_map_test_insert_i2t(hash, 123456789); tb_hash_map_test_insert_i2t(hash, 876543210); tb_hash_map_test_insert_i2t(hash, 76543210); tb_hash_map_test_insert_i2t(hash, 6543210); tb_hash_map_test_insert_i2t(hash, 543210); tb_hash_map_test_insert_i2t(hash, 43210); tb_hash_map_test_insert_i2t(hash, 3210); tb_hash_map_test_insert_i2t(hash, 210); tb_hash_map_test_insert_i2t(hash, 10); tb_hash_map_test_insert_i2t(hash, 0); tb_hash_map_test_dump(hash); // get tb_hash_map_test_get_i2t(hash, 0); tb_hash_map_test_get_i2t(hash, 1); tb_hash_map_test_get_i2t(hash, 12); tb_hash_map_test_get_i2t(hash, 123); tb_hash_map_test_get_i2t(hash, 1234); tb_hash_map_test_get_i2t(hash, 12345); tb_hash_map_test_get_i2t(hash, 123456); tb_hash_map_test_get_i2t(hash, 1234567); tb_hash_map_test_get_i2t(hash, 12345678); tb_hash_map_test_get_i2t(hash, 123456789); tb_hash_map_test_get_i2t(hash, 876543210); tb_hash_map_test_get_i2t(hash, 76543210); tb_hash_map_test_get_i2t(hash, 6543210); tb_hash_map_test_get_i2t(hash, 543210); tb_hash_map_test_get_i2t(hash, 43210); tb_hash_map_test_get_i2t(hash, 3210); tb_hash_map_test_get_i2t(hash, 210); tb_hash_map_test_get_i2t(hash, 10); tb_hash_map_test_get_i2t(hash, 0); // del tb_hash_map_test_remove_i2t(hash, 0); tb_hash_map_test_remove_i2t(hash, 1); tb_hash_map_test_remove_i2t(hash, 12); tb_hash_map_test_remove_i2t(hash, 123); tb_hash_map_test_remove_i2t(hash, 1234); tb_hash_map_test_remove_i2t(hash, 12345); tb_hash_map_test_remove_i2t(hash, 123456); tb_hash_map_test_remove_i2t(hash, 1234567); tb_hash_map_test_remove_i2t(hash, 12345678); tb_hash_map_test_remove_i2t(hash, 123456789); tb_hash_map_test_remove_i2t(hash, 123456789); tb_hash_map_test_dump(hash); // clear tb_hash_map_clear(hash); tb_hash_map_test_dump(hash); // exit tb_hash_map_exit(hash); } static tb_void_t tb_hash_map_test_i2t_perf() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(0, tb_element_long(), tb_element_true()); tb_assert_and_check_return(hash); // done __tb_volatile__ tb_size_t n = 100000; tb_hong_t t = tb_mclock(); while (n--) { tb_size_t i = tb_random_value(); tb_hash_map_test_insert_i2t(hash, i); tb_hash_map_test_get_i2t(hash, i); } t = tb_mclock() - t; tb_trace_i("i2t: time: %lld", t); // exit hash tb_hash_map_exit(hash); } static tb_bool_t tb_hash_map_test_walk_item(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t value) { // done tb_bool_t ok = tb_false; tb_hize_t* test = (tb_hize_t*)value; tb_hash_map_item_ref_t hash_item = (tb_hash_map_item_ref_t)item; if (hash_item) { if (!(((tb_size_t)hash_item->data >> 25) & 0x1)) ok = tb_true; else { test[0] += (tb_size_t)hash_item->name; test[1] += (tb_size_t)hash_item->data; test[2]++; } } // ok? return ok; } static tb_void_t tb_hash_map_test_walk_perf() { // init hash tb_hash_map_ref_t hash = tb_hash_map_init(0, tb_element_long(), tb_element_long()); tb_assert_and_check_return(hash); // reset random tb_random_reset(tb_true); // add items __tb_volatile__ tb_size_t n = 100000; while (n--) { tb_size_t i = tb_random_value(); tb_hash_map_test_insert_i2i(hash, i); tb_hash_map_test_get_i2i(hash, i); } // done tb_hong_t t = tb_mclock(); __tb_volatile__ tb_hize_t test[3] = {0}; tb_remove_if(hash, tb_hash_map_test_walk_item, (tb_cpointer_t)test); t = tb_mclock() - t; tb_trace_i("name: %llx, data: %llx, size: %llu ?= %u, time: %lld", test[0], test[1], test[2], tb_hash_map_size(hash), t); // exit tb_hash_map_exit(hash); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_hash_map_main(tb_int_t argc, tb_char_t** argv) { #if 1 tb_hash_map_test_s2i_func(); tb_hash_map_test_i2s_func(); tb_hash_map_test_m2m_func(); tb_hash_map_test_i2i_func(); tb_hash_map_test_i2t_func(); #endif #if 1 tb_hash_map_test_s2i_perf(); tb_hash_map_test_i2s_perf(); tb_hash_map_test_m2m_perf(); tb_hash_map_test_i2i_perf(); tb_hash_map_test_i2t_perf(); #endif #if 1 tb_hash_map_test_walk_perf(); #endif return 0; } tbox-1.7.6/src/demo/container/hash_set.c000066400000000000000000000016411467117505400201540ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_hash_set_main(tb_int_t argc, tb_char_t** argv) { // init hash tb_hash_set_ref_t hash = tb_hash_set_init(8, tb_element_str(tb_true)); if (hash) { tb_hash_set_insert(hash, "1"); tb_hash_set_insert(hash, "9"); tb_hash_set_insert(hash, "4"); tb_hash_set_insert(hash, "6"); tb_hash_set_insert(hash, "8"); tb_hash_set_insert(hash, "2"); tb_hash_set_insert(hash, "3"); tb_hash_set_insert(hash, "5"); tb_hash_set_insert(hash, "7"); tb_for_all_if (tb_char_t const*, s, hash, s) { tb_trace_i("%s", s); } tb_hash_set_exit(hash); } return 0; } tbox-1.7.6/src/demo/container/heap.c000066400000000000000000000130021467117505400172650ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * test */ static tb_long_t tb_test_heap_max_comp(tb_element_ref_t element, tb_cpointer_t ldata, tb_cpointer_t rdata) { return ((tb_p2u32(ldata) > tb_p2u32(rdata))? -1 : (tb_p2u32(ldata) < tb_p2u32(rdata))); } static tb_void_t tb_test_heap_min_func() { // init heap tb_heap_ref_t heap = tb_heap_init(16, tb_element_uint32()); tb_assert_and_check_return(heap); // reset rand tb_random_reset(tb_true); // make heap tb_size_t i = 0; for (i = 0; i < 100; i++) { // the value tb_uint32_t val = (tb_uint32_t)tb_random_range(0, 50); // trace // tb_trace_i("heap_min: put: %u", val); // put it tb_heap_put(heap, tb_u2p(val)); } // reset rand tb_random_reset(tb_true); // remove some values for (i = 0; i < 100; i++) { // the value tb_uint32_t val = (tb_uint32_t)tb_random_range(0, 50); // remove it? if (!(i & 3)) { tb_size_t itor = tb_find_all(heap, tb_u2p(val)); if (itor != tb_iterator_tail(heap)) tb_heap_remove(heap, itor); } } // append heap for (i = 0; i < 30; i++) { // the value tb_uint32_t val = (tb_uint32_t)tb_random_range(0, 50); // put it tb_heap_put(heap, tb_u2p(val)); } // trace tb_trace_i(""); // dump heap while (tb_heap_size(heap)) { // put it tb_uint32_t val = (tb_uint32_t)(tb_size_t)tb_heap_top(heap); // trace tb_trace_i("heap_min: pop: %u", val); // pop it tb_heap_pop(heap); } // exit heap tb_heap_exit(heap); } static tb_void_t tb_test_heap_min_perf() { // init heap tb_heap_ref_t heap = tb_heap_init(4096, tb_element_uint32()); tb_assert_and_check_return(heap); // reset rand tb_random_reset(tb_true); // init time tb_hong_t time = tb_mclock(); // profile __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 100000; __tb_volatile__ tb_size_t p; tb_used(&p); for (i = 0; i < n; i++) tb_heap_put(heap, (tb_pointer_t)(tb_size_t)tb_random_range(0, 50)); for (i = 0; tb_heap_size(heap); i++) { // get the top value tb_size_t v = (tb_size_t)tb_heap_top(heap); // check order tb_assert(!i || p <= v); // save the previous value p = v; // pop it tb_heap_pop(heap); } // exit time time = tb_mclock() - time; // trace tb_trace_i("heap_min: %lld ms", time); // exit heap tb_heap_exit(heap); } static tb_void_t tb_test_heap_max_func() { // init element tb_element_t element = tb_element_uint32(); element.comp = tb_test_heap_max_comp; // init heap tb_heap_ref_t heap = tb_heap_init(16, element); tb_assert_and_check_return(heap); // reset rand tb_random_reset(tb_true); // make heap tb_size_t i = 0; for (i = 0; i < 100; i++) { // the value tb_uint32_t val = (tb_uint32_t)tb_random_range(0, 50); // trace // tb_trace_i("heap_max: put: %u", val); // put it tb_heap_put(heap, tb_u2p(val)); } // remove some values for (i = 0; i < 100; i++) { // the value tb_uint32_t val = (tb_uint32_t)tb_random_range(0, 50); // remove it? if (!(i & 3)) { tb_size_t itor = tb_find_all(heap, tb_u2p(val)); if (itor != tb_iterator_tail(heap)) tb_heap_remove(heap, itor); } } // append heap for (i = 0; i < 30; i++) { // the value tb_uint32_t val = (tb_uint32_t)tb_random_range(0, 50); // put it tb_heap_put(heap, tb_u2p(val)); } // trace tb_trace_i(""); // dump heap while (tb_heap_size(heap)) { // put it tb_uint32_t val = (tb_uint32_t)(tb_size_t)tb_heap_top(heap); // trace tb_trace_i("heap_max: pop: %u", val); // pop it tb_heap_pop(heap); } // exit heap tb_heap_exit(heap); } static tb_void_t tb_test_heap_max_perf() { // init element tb_element_t element = tb_element_uint32(); element.comp = tb_test_heap_max_comp; // init heap tb_heap_ref_t heap = tb_heap_init(4096, element); tb_assert_and_check_return(heap); // init time tb_hong_t time = tb_mclock(); // profile __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 100000; __tb_volatile__ tb_size_t p; tb_used(&p); for (i = 0; i < n; i++) tb_heap_put(heap, (tb_pointer_t)(tb_size_t)tb_random_range(0, 50)); for (i = 0; tb_heap_size(heap); i++) { // get the top value tb_size_t v = (tb_size_t)tb_heap_top(heap); // check order tb_assert(!i || p >= v); // save the previous value p = v; // pop it tb_heap_pop(heap); } // exit time time = tb_mclock() - time; // trace tb_trace_i("heap_max: %lld ms", time); // exit heap tb_heap_exit(heap); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_heap_main(tb_int_t argc, tb_char_t** argv) { // element tb_test_heap_min_func(); tb_test_heap_max_func(); // performance tb_test_heap_min_perf(); tb_test_heap_max_perf(); return 0; } tbox-1.7.6/src/demo/container/list.c000066400000000000000000000623761467117505400173450ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * test */ static tb_void_t tb_list_insert_prev_test() { // init list tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list tb_size_t itor = tb_list_insert_head(list, (tb_pointer_t)0xd); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_insert_prev(list, itor, (tb_pointer_t)0xd); t = tb_mclock() - t; // trace tb_trace_i("tb_list_insert_prev(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(tb_list_size(list) == n + 1); tb_assert(tb_list_head(list) == (tb_pointer_t)0xd); tb_assert(tb_list_last(list) == (tb_pointer_t)0xd); // clear it tb_list_clear(list); // exit tb_list_exit(list); } static tb_void_t tb_list_insert_next_test() { // init list tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list tb_size_t itor = tb_list_insert_head(list, (tb_pointer_t)0xd); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_insert_next(list, itor, (tb_pointer_t)0xd); t = tb_mclock() - t; // trace tb_trace_i("tb_list_insert_next(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(tb_list_size(list) == n + 1); tb_assert(tb_list_head(list) == (tb_pointer_t)0xd); tb_assert(tb_list_last(list) == (tb_pointer_t)0xd); // clear it tb_list_clear(list); // exit tb_list_exit(list); } static tb_void_t tb_list_insert_head_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); t = tb_mclock() - t; // trace tb_trace_i("tb_list_insert_head(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(tb_list_size(list) == n); tb_assert(tb_list_head(list) == (tb_pointer_t)0xd); tb_assert(tb_list_last(list) == (tb_pointer_t)0xd); // clear it tb_list_clear(list); // exit tb_list_exit(list); } static tb_void_t tb_list_insert_tail_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_insert_tail(list, (tb_pointer_t)0xd); t = tb_mclock() - t; // trace tb_trace_i("tb_list_insert_tail(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(tb_list_size(list) == n); tb_assert(tb_list_head(list) == (tb_pointer_t)0xd); tb_assert(tb_list_last(list) == (tb_pointer_t)0xd); // clear it tb_list_clear(list); // exit tb_list_exit(list); } static tb_void_t tb_list_remove_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_size_t itor = tb_iterator_head(list); tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) itor = tb_list_remove(list, itor); t = tb_mclock() - t; // trace tb_trace_i("tb_list_remove(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(!tb_list_size(list)); // exit tb_list_exit(list); } static tb_void_t tb_list_remove_head_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_remove_head(list); t = tb_mclock() - t; // trace tb_trace_i("tb_list_remove_head(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(!tb_list_size(list)); // exit tb_list_exit(list); } static tb_void_t tb_list_remove_last_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_remove_last(list); t = tb_mclock() - t; // trace tb_trace_i("tb_list_remove_last(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(!tb_list_size(list)); // exit tb_list_exit(list); } static tb_void_t tb_list_replace_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_size_t itor = tb_iterator_head(list); tb_size_t tail = tb_iterator_tail(list); tb_hong_t t = tb_mclock(); for (; itor != tail; itor = tb_iterator_next(list, itor)) tb_list_replace(list, itor, (tb_pointer_t)0xe); t = tb_mclock() - t; // trace tb_trace_i("tb_list_replace(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(tb_list_size(list) == n); tb_assert(tb_list_head(list) == (tb_pointer_t)0xe); tb_assert(tb_list_last(list) == (tb_pointer_t)0xe); // exit tb_list_exit(list); } static tb_void_t tb_list_replace_head_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_replace_head(list, (tb_pointer_t)0xe); t = tb_mclock() - t; // trace tb_trace_i("tb_list_replace_head(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(tb_list_size(list) == n); tb_assert(tb_list_head(list) == (tb_pointer_t)0xe); // exit tb_list_exit(list); } static tb_void_t tb_list_replace_last_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_list_replace_last(list, (tb_pointer_t)0xe); t = tb_mclock() - t; // trace tb_trace_i("tb_list_replace_last(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // check tb_assert(tb_list_size(list) == n); tb_assert(tb_list_last(list) == (tb_pointer_t)0xe); // exit tb_list_exit(list); } static tb_void_t tb_list_iterator_next_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_size()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); tb_for_all(tb_size_t, item, list) tb_used(item); t = tb_mclock() - t; // trace tb_trace_i("tb_list_iterator_next(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // exit tb_list_exit(list); } static tb_void_t tb_list_iterator_prev_test() { // init tb_list_ref_t list = tb_list_init(0, tb_element_size()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); tb_rfor_all(tb_size_t, item, list) tb_used(item); t = tb_mclock() - t; // trace tb_trace_i("tb_list_iterator_prev(%d): %lld ms, size: %d, maxn: %d", n, t, tb_list_size(list), tb_list_maxn(list)); // exit tb_list_exit(list); } static tb_void_t tb_list_int_dump(tb_list_ref_t list) { // trace tb_trace_i("tb_int_t size: %d, maxn: %d", tb_list_size(list), tb_list_maxn(list)); // done tb_for_all(tb_char_t*, item, list) { // trace tb_trace_i("tb_int_t at[%lx]: %x", item_itor, item); } } static tb_void_t tb_list_int_test() { // done tb_list_ref_t list = tb_null; tb_size_t i; tb_size_t j; do { // init list list = tb_list_init(0, tb_element_long()); tb_assert_and_check_break(list); // trace tb_trace_i("============================================================="); tb_trace_i("insert:"); // insert head tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); tb_list_insert_head(list, (tb_pointer_t)0xa); // insert tail i = tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); tb_list_insert_tail(list, (tb_pointer_t)0xf); // insert prev j = tb_list_insert_prev(list, i, (tb_pointer_t)0); tb_list_insert_prev(list, i, (tb_pointer_t)1); tb_list_insert_prev(list, i, (tb_pointer_t)2); tb_list_insert_prev(list, i, (tb_pointer_t)3); tb_list_insert_prev(list, i, (tb_pointer_t)4); tb_list_insert_prev(list, i, (tb_pointer_t)5); tb_list_insert_prev(list, i, (tb_pointer_t)6); tb_list_insert_prev(list, i, (tb_pointer_t)7); tb_list_insert_prev(list, i, (tb_pointer_t)8); tb_list_insert_prev(list, i, (tb_pointer_t)9); // insert head tb_list_insert_head(list, (tb_pointer_t)4); tb_list_insert_head(list, (tb_pointer_t)3); tb_list_insert_head(list, (tb_pointer_t)2); tb_list_insert_head(list, (tb_pointer_t)1); tb_list_insert_head(list, (tb_pointer_t)0); // insert tail tb_list_insert_tail(list, (tb_pointer_t)5); tb_list_insert_tail(list, (tb_pointer_t)6); tb_list_insert_tail(list, (tb_pointer_t)7); tb_list_insert_tail(list, (tb_pointer_t)8); tb_list_insert_tail(list, (tb_pointer_t)9); // dump tb_list_int_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("remove:"); // remove head tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); // remove last tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); // remove j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); // dump tb_list_int_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("replace:"); // replace head tb_list_replace_head(list, (tb_pointer_t)0); // replace last tb_list_replace_last(list, (tb_pointer_t)1); // dump tb_list_int_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("moveto:"); // move to head and tail tb_list_moveto_head(list, tb_iterator_last(list)); tb_list_moveto_tail(list, tb_iterator_next(list, tb_iterator_head(list))); // dump tb_list_int_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("clear:"); // clear tb_list_clear(list); // dump tb_list_int_dump(list); } while (0); // exit list if (list) tb_list_exit(list); } static tb_void_t tb_list_str_dump(tb_list_ref_t list) { // trace tb_trace_i("str size: %d, maxn: %d", tb_list_size(list), tb_list_maxn(list)); // done tb_for_all (tb_char_t*, item, list) { // trace tb_trace_i("str at[%lx]: %s", item_itor, item); } } static tb_void_t tb_list_str_test() { // done tb_list_ref_t list = tb_null; tb_size_t i; tb_size_t j; do { // init list list = tb_list_init(0, tb_element_str(tb_true)); tb_assert_and_check_break(list); // trace tb_trace_i("============================================================="); tb_trace_i("insert:"); // insert head tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); // insert tail i = tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); // insert prev j = tb_list_insert_prev(list, i, "0000000000"); tb_list_insert_prev(list, i, "1111111111"); tb_list_insert_prev(list, i, "2222222222"); tb_list_insert_prev(list, i, "3333333333"); tb_list_insert_prev(list, i, "4444444444"); tb_list_insert_prev(list, i, "5555555555"); tb_list_insert_prev(list, i, "6666666666"); tb_list_insert_prev(list, i, "7777777777"); tb_list_insert_prev(list, i, "8888888888"); tb_list_insert_prev(list, i, "9999999999"); // insert head tb_list_insert_head(list, "4444444444"); tb_list_insert_head(list, "3333333333"); tb_list_insert_head(list, "2222222222"); tb_list_insert_head(list, "1111111111"); tb_list_insert_head(list, "0000000000"); // insert tail tb_list_insert_tail(list, "5555555555"); tb_list_insert_tail(list, "6666666666"); tb_list_insert_tail(list, "7777777777"); tb_list_insert_tail(list, "8888888888"); tb_list_insert_tail(list, "9999999999"); // dump tb_list_str_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("remove:"); // remove head tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); // remove last tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); // remove j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); // dump tb_list_str_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("replace:"); // replace head tb_list_replace_head(list, "0000000000"); // replace last tb_list_replace_last(list, "1111111111"); // dump tb_list_str_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("moveto:"); // move to head and tail tb_list_moveto_head(list, tb_iterator_last(list)); tb_list_moveto_tail(list, tb_iterator_next(list, tb_iterator_head(list))); // dump tb_list_str_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("clear:"); // clear tb_list_clear(list); // dump tb_list_str_dump(list); } while (0); // exit list if (list) tb_list_exit(list); } static tb_void_t tb_list_mem_free(tb_element_ref_t element, tb_pointer_t buff) { tb_trace_i("ifm free: %s, priv: %s", buff, element->priv); } static tb_void_t tb_list_mem_dump(tb_list_ref_t list) { // trace tb_trace_i("ifm size: %d, maxn: %d", tb_list_size(list), tb_list_maxn(list)); // done tb_for_all (tb_char_t*, item, list) { // trace tb_trace_i("ifm at[%lx]: %s", item_itor, item); } } static tb_void_t tb_list_mem_test() { // done tb_list_ref_t list = tb_null; tb_size_t i; tb_size_t j; do { // init list list = tb_list_init(0, tb_element_mem(11, tb_list_mem_free, "mem")); tb_assert_and_check_break(list); // trace tb_trace_i("============================================================="); tb_trace_i("insert:"); // insert head tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); tb_list_insert_head(list, "AAAAAAAAAA"); // insert tail i = tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); tb_list_insert_tail(list, "FFFFFFFFFF"); // insert prev j = tb_list_insert_prev(list, i, "0000000000"); tb_list_insert_prev(list, i, "1111111111"); tb_list_insert_prev(list, i, "2222222222"); tb_list_insert_prev(list, i, "3333333333"); tb_list_insert_prev(list, i, "4444444444"); tb_list_insert_prev(list, i, "5555555555"); tb_list_insert_prev(list, i, "6666666666"); tb_list_insert_prev(list, i, "7777777777"); tb_list_insert_prev(list, i, "8888888888"); tb_list_insert_prev(list, i, "9999999999"); // insert head tb_list_insert_head(list, "4444444444"); tb_list_insert_head(list, "3333333333"); tb_list_insert_head(list, "2222222222"); tb_list_insert_head(list, "1111111111"); tb_list_insert_head(list, "0000000000"); // insert tail tb_list_insert_tail(list, "5555555555"); tb_list_insert_tail(list, "6666666666"); tb_list_insert_tail(list, "7777777777"); tb_list_insert_tail(list, "8888888888"); tb_list_insert_tail(list, "9999999999"); // dump tb_list_mem_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("remove:"); // remove head tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); tb_list_remove_head(list); // remove last tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); tb_list_remove_last(list); // remove j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); j = tb_list_remove(list, j); // dump tb_list_mem_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("replace:"); // replace head tb_list_replace_head(list, "0000000000"); // replace last tb_list_replace_last(list, "1111111111"); // dump tb_list_mem_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("moveto:"); // move to head and tail tb_list_moveto_head(list, tb_iterator_last(list)); tb_list_moveto_tail(list, tb_iterator_next(list, tb_iterator_head(list))); // dump tb_list_mem_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("clear:"); // clear tb_list_clear(list); // dump tb_list_mem_dump(list); } while (0); // exit list if (list) tb_list_exit(list); } static tb_void_t tb_list_perf_test() { // insert tb_list_insert_prev_test(); tb_list_insert_next_test(); tb_list_insert_head_test(); tb_list_insert_tail_test(); // remove tb_list_remove_test(); tb_list_remove_head_test(); tb_list_remove_last_test(); // replace tb_list_replace_test(); tb_list_replace_head_test(); tb_list_replace_last_test(); // iterator tb_list_iterator_next_test(); tb_list_iterator_prev_test(); } static tb_bool_t tb_list_test_walk_item(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t value) { // done tb_hize_t* test = (tb_hize_t*)value; tb_size_t i = (tb_size_t)item; tb_bool_t ok = tb_false; if (!((i >> 25) & 0x1)) ok = tb_true; else { test[0] += i; test[1]++; } // ok? return ok; } static tb_void_t tb_list_walk_perf() { // init list tb_list_ref_t list = tb_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t n = 100000; while (n--) tb_list_insert_tail(list, (tb_pointer_t)(tb_size_t)tb_random_value()); // done tb_hong_t t = tb_mclock(); __tb_volatile__ tb_hize_t test[2] = {0}; tb_remove_if(list, tb_list_test_walk_item, (tb_pointer_t)test); t = tb_mclock() - t; // trace tb_trace_i("item: %llx, size: %llu ?= %u, time: %lld", test[0], test[1], tb_list_size(list), t); // exit list tb_list_exit(list); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_list_main(tb_int_t argc, tb_char_t** argv) { tb_list_int_test(); tb_list_str_test(); tb_list_mem_test(); #if 1 tb_list_perf_test(); #endif #if 1 tb_list_walk_perf(); #endif return 0; } tbox-1.7.6/src/demo/container/list_entry.c000066400000000000000000000073461467117505400205620ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the demo entry type typedef struct __tb_demo_entry_t { // the list entry tb_list_entry_t entry; // the data tb_size_t data; }tb_demo_entry_t; /* ////////////////////////////////////////////////////////////////////////////////////// * comparer */ static tb_void_t tb_demo_entry_copy(tb_pointer_t litem, tb_pointer_t ritem) { // check tb_assert(litem && ritem); // copy it ((tb_demo_entry_t*)litem)->data = ((tb_demo_entry_t*)ritem)->data; } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_list_entry_main(tb_int_t argc, tb_char_t** argv) { // init the entries tb_demo_entry_t entries[12] = { {{0}, 0} , {{0}, 1} , {{0}, 2} , {{0}, 3} , {{0}, 4} , {{0}, 5} , {{0}, 6} , {{0}, 7} , {{0}, 8} , {{0}, 9} , {{0}, 10} , {{0}, 11} }; // init the list tb_list_entry_head_t list; tb_list_entry_init(&list, tb_demo_entry_t, entry, tb_demo_entry_copy); // insert entries tb_list_entry_insert_tail(&list, &entries[5].entry); tb_list_entry_insert_tail(&list, &entries[6].entry); tb_list_entry_insert_tail(&list, &entries[7].entry); tb_list_entry_insert_tail(&list, &entries[8].entry); tb_list_entry_insert_tail(&list, &entries[9].entry); tb_list_entry_insert_head(&list, &entries[4].entry); tb_list_entry_insert_head(&list, &entries[3].entry); tb_list_entry_insert_head(&list, &entries[2].entry); tb_list_entry_insert_head(&list, &entries[1].entry); tb_list_entry_insert_head(&list, &entries[0].entry); // the entry tb_demo_entry_t* entry = (tb_demo_entry_t*)tb_list_entry(&list, &entries[5].entry); tb_trace_i("entry: %lu", entry->data); tb_trace_i(""); // walk it tb_trace_i("insert: %lu", tb_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item0, tb_list_entry_itor(&list), item0) { tb_trace_i("%lu", item0->data); } // trace tb_trace_i(""); // replace entries tb_list_entry_replace_head(&list, &entries[10].entry); tb_list_entry_replace_last(&list, &entries[11].entry); // walk it tb_trace_i("replace: %lu", tb_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item1, tb_list_entry_itor(&list), item1) { tb_trace_i("%lu", item1->data); } // trace tb_trace_i(""); // remove entries tb_list_entry_remove_head(&list); tb_list_entry_remove_last(&list); // walk it tb_trace_i("remove: %lu", tb_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item2, tb_list_entry_itor(&list), item2) { tb_trace_i("%lu", item2->data); } // trace tb_trace_i(""); // moveto entries tb_list_entry_ref_t head = tb_list_entry_head(&list); tb_list_entry_moveto_head(&list, tb_list_entry_last(&list)); tb_list_entry_moveto_tail(&list, head); // walk it tb_trace_i("moveto: %lu", tb_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item3, tb_list_entry_itor(&list), item3) { tb_trace_i("%lu", item3->data); } // trace tb_trace_i(""); // clear entries tb_list_entry_clear(&list); // walk it tb_trace_i("clear: %lu", tb_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item5, tb_list_entry_itor(&list), item5) { tb_trace_i("%lu", item5->data); } // exit the list tb_list_entry_exit(&list); // trace tb_trace_i(""); return 0; } tbox-1.7.6/src/demo/container/queue.c000066400000000000000000000173311467117505400175050ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_queue_put_and_pop_test() { // init tb_queue_ref_t queue = tb_queue_init(10, tb_element_long()); tb_assert_and_check_return(queue); // make queue tb_queue_put(queue, (tb_pointer_t)0); tb_queue_put(queue, (tb_pointer_t)1); tb_queue_put(queue, (tb_pointer_t)2); tb_queue_put(queue, (tb_pointer_t)3); tb_queue_put(queue, (tb_pointer_t)4); tb_queue_put(queue, (tb_pointer_t)5); tb_queue_put(queue, (tb_pointer_t)6); tb_queue_put(queue, (tb_pointer_t)7); tb_queue_put(queue, (tb_pointer_t)8); tb_queue_put(queue, (tb_pointer_t)9); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) { tb_queue_pop(queue); tb_queue_put(queue, (tb_pointer_t)0xf); } t = tb_mclock() - t; // trace tb_trace_i("tb_queue_put_and_pop(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_queue_size(queue), tb_queue_maxn(queue)); // check tb_assert(tb_queue_size(queue) == 10); tb_assert(tb_queue_head(queue) == (tb_pointer_t)0xf); tb_assert(tb_queue_last(queue) == (tb_pointer_t)0xf); // clear it tb_queue_clear(queue); tb_assert(!tb_queue_size(queue)); // exit tb_queue_exit(queue); } static tb_void_t tb_queue_iterator_next_test() { // init tb_queue_ref_t queue = tb_queue_init(0, tb_element_long()); tb_assert_and_check_return(queue); // make queue tb_size_t n = 1000000; while (n--) tb_queue_put(queue, (tb_pointer_t)0xf); // done tb_hong_t t = tb_mclock(); tb_for_all (tb_char_t*, item, queue) tb_used(item); t = tb_mclock() - t; // trace tb_trace_i("tb_queue_iterator_next(%lu): %lld ms, size: %lu, maxn: %lu", 1000000, t, tb_queue_size(queue), tb_queue_maxn(queue)); // exit tb_queue_exit(queue); } static tb_void_t tb_queue_int_dump(tb_queue_ref_t queue) { tb_trace_i("tb_int_t size: %lu, maxn: %lu", tb_queue_size(queue), tb_queue_maxn(queue)); tb_for_all (tb_char_t*, item, queue) { tb_trace_i("tb_int_t at[%lu]: %u", item_itor, item); } } static tb_void_t tb_queue_int_test() { tb_queue_ref_t queue = tb_queue_init(10, tb_element_long()); tb_assert_and_check_return(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_queue_put(queue, (tb_pointer_t)0); tb_queue_put(queue, (tb_pointer_t)1); tb_queue_put(queue, (tb_pointer_t)2); tb_queue_put(queue, (tb_pointer_t)3); tb_queue_put(queue, (tb_pointer_t)4); tb_queue_put(queue, (tb_pointer_t)5); tb_queue_put(queue, (tb_pointer_t)6); tb_queue_put(queue, (tb_pointer_t)7); tb_queue_put(queue, (tb_pointer_t)8); tb_queue_put(queue, (tb_pointer_t)9); tb_queue_int_dump(queue); tb_trace_i("============================================================="); tb_trace_i("pop:"); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_int_dump(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_queue_put(queue, (tb_pointer_t)0); tb_queue_put(queue, (tb_pointer_t)1); tb_queue_put(queue, (tb_pointer_t)2); tb_queue_put(queue, (tb_pointer_t)3); tb_queue_put(queue, (tb_pointer_t)4); tb_queue_int_dump(queue); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_queue_clear(queue); tb_queue_int_dump(queue); tb_queue_exit(queue); } static tb_void_t tb_queue_str_dump(tb_queue_ref_t queue) { tb_trace_i("str size: %lu, maxn: %lu", tb_queue_size(queue), tb_queue_maxn(queue)); tb_for_all (tb_char_t*, item, queue) { tb_trace_i("str at[%lu]: %s", item_itor, item); } } static tb_void_t tb_queue_str_test() { tb_queue_ref_t queue = tb_queue_init(10, tb_element_str(tb_true)); tb_assert_and_check_return(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_queue_put(queue, "0000000000"); tb_queue_put(queue, "1111111111"); tb_queue_put(queue, "2222222222"); tb_queue_put(queue, "3333333333"); tb_queue_put(queue, "4444444444"); tb_queue_put(queue, "5555555555"); tb_queue_put(queue, "6666666666"); tb_queue_put(queue, "7777777777"); tb_queue_put(queue, "8888888888"); tb_queue_put(queue, "9999999999"); tb_queue_str_dump(queue); tb_trace_i("============================================================="); tb_trace_i("pop:"); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_str_dump(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_queue_put(queue, "0000000000"); tb_queue_put(queue, "1111111111"); tb_queue_put(queue, "2222222222"); tb_queue_put(queue, "3333333333"); tb_queue_put(queue, "4444444444"); tb_queue_str_dump(queue); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_queue_clear(queue); tb_queue_str_dump(queue); tb_queue_exit(queue); } static tb_void_t tb_queue_mem_free(tb_element_ref_t element, tb_pointer_t buff) { tb_trace_i("ifm free: %s, priv: %s", buff, element->priv); } static tb_void_t tb_queue_mem_dump(tb_queue_ref_t queue) { tb_trace_i("ifm size: %lu, maxn: %lu", tb_queue_size(queue), tb_queue_maxn(queue)); tb_for_all (tb_char_t*, item, queue) { tb_trace_i("ifm at[%lu]: %s", item_itor, item); } } static tb_void_t tb_queue_mem_test() { tb_queue_ref_t queue = tb_queue_init(10, tb_element_mem(11, tb_queue_mem_free, "ifm")); tb_assert_and_check_return(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_queue_put(queue, "0000000000"); tb_queue_put(queue, "1111111111"); tb_queue_put(queue, "2222222222"); tb_queue_put(queue, "3333333333"); tb_queue_put(queue, "4444444444"); tb_queue_put(queue, "5555555555"); tb_queue_put(queue, "6666666666"); tb_queue_put(queue, "7777777777"); tb_queue_put(queue, "8888888888"); tb_queue_put(queue, "9999999999"); tb_queue_mem_dump(queue); tb_trace_i("============================================================="); tb_trace_i("pop:"); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_pop(queue); tb_queue_mem_dump(queue); tb_trace_i("============================================================="); tb_trace_i("put:"); tb_queue_put(queue, "0000000000"); tb_queue_put(queue, "1111111111"); tb_queue_put(queue, "2222222222"); tb_queue_put(queue, "3333333333"); tb_queue_put(queue, "4444444444"); tb_queue_mem_dump(queue); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_queue_clear(queue); tb_queue_mem_dump(queue); tb_queue_exit(queue); } static tb_void_t tb_queue_perf_test() { tb_queue_put_and_pop_test(); tb_queue_iterator_next_test(); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_queue_main(tb_int_t argc, tb_char_t** argv) { tb_queue_int_test(); tb_queue_str_test(); tb_queue_mem_test(); tb_queue_perf_test(); return 0; } tbox-1.7.6/src/demo/container/single_list.c000066400000000000000000000554441467117505400207040ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * test */ static tb_void_t tb_single_list_insert_next_test() { // init list tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list tb_size_t itor = tb_single_list_insert_head(list, (tb_pointer_t)0xd); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_single_list_insert_next(list, itor, (tb_pointer_t)0xd); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_insert_next(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(tb_single_list_size(list) == n + 1); tb_assert(tb_single_list_head(list) == (tb_pointer_t)0xd); tb_assert(tb_single_list_last(list) == (tb_pointer_t)0xd); // clear it tb_single_list_clear(list); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_insert_head_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_single_list_insert_head(list, (tb_pointer_t)0xd); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_insert_head(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(tb_single_list_size(list) == n); tb_assert(tb_single_list_head(list) == (tb_pointer_t)0xd); tb_assert(tb_single_list_last(list) == (tb_pointer_t)0xd); // clear it tb_single_list_clear(list); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_insert_tail_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // done __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_single_list_insert_tail(list, (tb_pointer_t)0xd); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_insert_tail(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(tb_single_list_size(list) == n); tb_assert(tb_single_list_head(list) == (tb_pointer_t)0xd); tb_assert(tb_single_list_last(list) == (tb_pointer_t)0xd); // clear it tb_single_list_clear(list); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_remove_next_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_single_list_insert_head(list, (tb_pointer_t)0xd); // done tb_size_t itor = tb_iterator_head(list); tb_hong_t t = tb_mclock(); for (i = 0, n--; i < n; i++) tb_single_list_remove_next(list, itor); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_remove(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(1 == tb_single_list_size(list)); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_remove_head_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_single_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_single_list_remove_head(list); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_remove_head(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(!tb_single_list_size(list)); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_replace_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_single_list_insert_head(list, (tb_pointer_t)0xd); // done tb_size_t itor = tb_iterator_head(list); tb_size_t tail = tb_iterator_tail(list); tb_hong_t t = tb_mclock(); for (; itor != tail; itor = tb_iterator_next(list, itor)) tb_single_list_replace(list, itor, (tb_pointer_t)0xe); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_replace(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(tb_single_list_size(list) == n); tb_assert(tb_single_list_head(list) == (tb_pointer_t)0xe); tb_assert(tb_single_list_last(list) == (tb_pointer_t)0xe); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_replace_head_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_single_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_single_list_replace_head(list, (tb_pointer_t)0xe); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_replace_head(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(tb_single_list_size(list) == n); tb_assert(tb_single_list_head(list) == (tb_pointer_t)0xe); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_replace_last_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_single_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_single_list_replace_last(list, (tb_pointer_t)0xe); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_replace_last(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // check tb_assert(tb_single_list_size(list) == n); tb_assert(tb_single_list_last(list) == (tb_pointer_t)0xe); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_iterator_next_test() { // init tb_single_list_ref_t list = tb_single_list_init(0, tb_element_size()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 1000000; for (i = 0; i < n; i++) tb_single_list_insert_head(list, (tb_pointer_t)0xd); // done tb_hong_t t = tb_mclock(); tb_for_all(tb_size_t, item, list) tb_used(item); t = tb_mclock() - t; // trace tb_trace_i("tb_single_list_iterator_next(%d): %lld ms, size: %d, maxn: %d", n, t, tb_single_list_size(list), tb_single_list_maxn(list)); // exit tb_single_list_exit(list); } static tb_void_t tb_single_list_int_dump(tb_single_list_ref_t list) { // trace tb_trace_i("tb_int_t size: %d, maxn: %d", tb_single_list_size(list), tb_single_list_maxn(list)); // done tb_for_all(tb_char_t*, item, list) { // trace tb_trace_i("tb_int_t at[%lx]: %x", item_itor, item); } } static tb_void_t tb_single_list_int_test() { // done tb_single_list_ref_t list = tb_null; tb_size_t i; do { // init list list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_break(list); // trace tb_trace_i("============================================================="); tb_trace_i("insert:"); // insert head i = tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); tb_single_list_insert_head(list, (tb_pointer_t)0xa); // insert tail tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); tb_single_list_insert_tail(list, (tb_pointer_t)0xf); // insert next tb_single_list_insert_next(list, i, (tb_pointer_t)0); tb_single_list_insert_next(list, i, (tb_pointer_t)1); tb_single_list_insert_next(list, i, (tb_pointer_t)2); tb_single_list_insert_next(list, i, (tb_pointer_t)3); tb_single_list_insert_next(list, i, (tb_pointer_t)4); tb_single_list_insert_next(list, i, (tb_pointer_t)5); tb_single_list_insert_next(list, i, (tb_pointer_t)6); tb_single_list_insert_next(list, i, (tb_pointer_t)7); tb_single_list_insert_next(list, i, (tb_pointer_t)8); tb_single_list_insert_next(list, i, (tb_pointer_t)9); // insert head tb_single_list_insert_head(list, (tb_pointer_t)4); tb_single_list_insert_head(list, (tb_pointer_t)3); tb_single_list_insert_head(list, (tb_pointer_t)2); tb_single_list_insert_head(list, (tb_pointer_t)1); tb_single_list_insert_head(list, (tb_pointer_t)0); // dump tb_single_list_int_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("remove:"); // remove head tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); // remove tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); // dump tb_single_list_int_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("replace:"); // replace head tb_single_list_replace_head(list, (tb_pointer_t)0); // replace last tb_single_list_replace_last(list, (tb_pointer_t)1); // dump tb_single_list_int_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("clear:"); // clear tb_single_list_clear(list); // dump tb_single_list_int_dump(list); } while (0); // exit list if (list) tb_single_list_exit(list); } static tb_void_t tb_single_list_str_dump(tb_single_list_ref_t list) { // trace tb_trace_i("str size: %d, maxn: %d", tb_single_list_size(list), tb_single_list_maxn(list)); // done tb_for_all (tb_char_t*, item, list) { // trace tb_trace_i("str at[%lx]: %s", item_itor, item); } } static tb_void_t tb_single_list_str_test() { // done tb_single_list_ref_t list = tb_null; tb_size_t i; do { // init list list = tb_single_list_init(0, tb_element_str(tb_true)); tb_assert_and_check_break(list); // trace tb_trace_i("============================================================="); tb_trace_i("insert:"); // insert head i = tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); // insert tail tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); // insert next tb_single_list_insert_next(list, i, "0000000000"); tb_single_list_insert_next(list, i, "1111111111"); tb_single_list_insert_next(list, i, "2222222222"); tb_single_list_insert_next(list, i, "3333333333"); tb_single_list_insert_next(list, i, "4444444444"); tb_single_list_insert_next(list, i, "5555555555"); tb_single_list_insert_next(list, i, "6666666666"); tb_single_list_insert_next(list, i, "7777777777"); tb_single_list_insert_next(list, i, "8888888888"); tb_single_list_insert_next(list, i, "9999999999"); // insert head tb_single_list_insert_head(list, "4444444444"); tb_single_list_insert_head(list, "3333333333"); tb_single_list_insert_head(list, "2222222222"); tb_single_list_insert_head(list, "1111111111"); tb_single_list_insert_head(list, "0000000000"); // dump tb_single_list_str_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("remove:"); // remove head tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); // remove tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); // dump tb_single_list_str_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("replace:"); // replace head tb_single_list_replace_head(list, "0000000000"); // replace last tb_single_list_replace_last(list, "1111111111"); // dump tb_single_list_str_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("clear:"); // clear tb_single_list_clear(list); // dump tb_single_list_str_dump(list); } while (0); // exit list if (list) tb_single_list_exit(list); } static tb_void_t tb_single_list_mem_free(tb_element_ref_t element, tb_pointer_t buff) { tb_trace_i("ifm free: %s, priv: %s", buff, element->priv); } static tb_void_t tb_single_list_mem_dump(tb_single_list_ref_t list) { // trace tb_trace_i("ifm size: %d, maxn: %d", tb_single_list_size(list), tb_single_list_maxn(list)); // done tb_for_all (tb_char_t*, item, list) { // trace tb_trace_i("ifm at[%lx]: %s", item_itor, item); } } static tb_void_t tb_single_list_mem_test() { // done tb_single_list_ref_t list = tb_null; tb_size_t i; do { // init list list = tb_single_list_init(0, tb_element_mem(11, tb_single_list_mem_free, "mem")); tb_assert_and_check_break(list); // trace tb_trace_i("============================================================="); tb_trace_i("insert:"); // insert head i = tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); tb_single_list_insert_head(list, "AAAAAAAAAA"); // insert tail tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); tb_single_list_insert_tail(list, "FFFFFFFFFF"); // insert next tb_single_list_insert_next(list, i, "0000000000"); tb_single_list_insert_next(list, i, "1111111111"); tb_single_list_insert_next(list, i, "2222222222"); tb_single_list_insert_next(list, i, "3333333333"); tb_single_list_insert_next(list, i, "4444444444"); tb_single_list_insert_next(list, i, "5555555555"); tb_single_list_insert_next(list, i, "6666666666"); tb_single_list_insert_next(list, i, "7777777777"); tb_single_list_insert_next(list, i, "8888888888"); tb_single_list_insert_next(list, i, "9999999999"); // insert head tb_single_list_insert_head(list, "4444444444"); tb_single_list_insert_head(list, "3333333333"); tb_single_list_insert_head(list, "2222222222"); tb_single_list_insert_head(list, "1111111111"); tb_single_list_insert_head(list, "0000000000"); // dump tb_single_list_mem_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("remove:"); // remove head tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); tb_single_list_remove_head(list); // remove tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); tb_single_list_remove_next(list, i); // dump tb_single_list_mem_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("replace:"); // replace head tb_single_list_replace_head(list, "0000000000"); // replace last tb_single_list_replace_last(list, "1111111111"); // dump tb_single_list_mem_dump(list); // trace tb_trace_i("============================================================="); tb_trace_i("clear:"); // clear tb_single_list_clear(list); // dump tb_single_list_mem_dump(list); } while (0); // exit list if (list) tb_single_list_exit(list); } static tb_void_t tb_single_list_perf_test() { // insert tb_single_list_insert_next_test(); tb_single_list_insert_head_test(); tb_single_list_insert_tail_test(); // remove tb_single_list_remove_next_test(); tb_single_list_remove_head_test(); // replace tb_single_list_replace_test(); tb_single_list_replace_head_test(); tb_single_list_replace_last_test(); // iterator tb_single_list_iterator_next_test(); } static tb_bool_t tb_single_list_test_walk_item(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t value) { // done tb_hize_t* test = (tb_hize_t*)value; tb_size_t i = (tb_size_t)item; tb_bool_t ok = tb_false; if (!((i >> 25) & 0x1)) ok = tb_true; else { test[0] += i; test[1]++; } // ok? return ok; } static tb_void_t tb_single_list_walk_perf() { // init list tb_single_list_ref_t list = tb_single_list_init(0, tb_element_long()); tb_assert_and_check_return(list); // make list __tb_volatile__ tb_size_t n = 100000; while (n--) tb_single_list_insert_tail(list, (tb_pointer_t)(tb_size_t)tb_random_value()); // done tb_hong_t t = tb_mclock(); __tb_volatile__ tb_hize_t test[2] = {0}; tb_remove_if(list, tb_single_list_test_walk_item, (tb_pointer_t)test); t = tb_mclock() - t; // trace tb_trace_i("item: %llx, size: %llu ?= %u, time: %lld", test[0], test[1], tb_single_list_size(list), t); // exit list tb_single_list_exit(list); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_single_list_main(tb_int_t argc, tb_char_t** argv) { tb_single_list_int_test(); tb_single_list_str_test(); tb_single_list_mem_test(); #if 1 tb_single_list_perf_test(); #endif #if 1 tb_single_list_walk_perf(); #endif return 0; } tbox-1.7.6/src/demo/container/single_list_entry.c000066400000000000000000000066371467117505400221250ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the demo entry type typedef struct __tb_demo_entry_t { // the list entry tb_single_list_entry_t entry; // the data tb_size_t data; }tb_demo_entry_t; /* ////////////////////////////////////////////////////////////////////////////////////// * comparer */ static tb_void_t tb_demo_entry_copy(tb_pointer_t litem, tb_pointer_t ritem) { // check tb_assert(litem && ritem); // copy it ((tb_demo_entry_t*)litem)->data = ((tb_demo_entry_t*)ritem)->data; } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_single_list_entry_main(tb_int_t argc, tb_char_t** argv) { // init the entries tb_demo_entry_t entries[12] = { {{0}, 0} , {{0}, 1} , {{0}, 2} , {{0}, 3} , {{0}, 4} , {{0}, 5} , {{0}, 6} , {{0}, 7} , {{0}, 8} , {{0}, 9} , {{0}, 10} , {{0}, 11} }; // init the list tb_single_list_entry_head_t list; tb_single_list_entry_init(&list, tb_demo_entry_t, entry, tb_demo_entry_copy); // insert entries tb_single_list_entry_insert_tail(&list, &entries[5].entry); tb_single_list_entry_insert_tail(&list, &entries[6].entry); tb_single_list_entry_insert_tail(&list, &entries[7].entry); tb_single_list_entry_insert_tail(&list, &entries[8].entry); tb_single_list_entry_insert_tail(&list, &entries[9].entry); tb_single_list_entry_insert_head(&list, &entries[4].entry); tb_single_list_entry_insert_head(&list, &entries[3].entry); tb_single_list_entry_insert_head(&list, &entries[2].entry); tb_single_list_entry_insert_head(&list, &entries[1].entry); tb_single_list_entry_insert_head(&list, &entries[0].entry); // the entry tb_demo_entry_t* entry = (tb_demo_entry_t*)tb_single_list_entry(&list, &entries[5].entry); tb_trace_i("entry: %lu", entry->data); tb_trace_i(""); // walk it tb_trace_i("insert: %lu", tb_single_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item0, tb_single_list_entry_itor(&list), item0) { tb_trace_i("%lu", item0->data); } // trace tb_trace_i(""); // replace entries tb_single_list_entry_replace_head(&list, &entries[10].entry); // walk it tb_trace_i("replace: %lu", tb_single_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item1, tb_single_list_entry_itor(&list), item1) { tb_trace_i("%lu", item1->data); } // trace tb_trace_i(""); // remove entries tb_single_list_entry_remove_head(&list); // walk it tb_trace_i("remove: %lu", tb_single_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item2, tb_single_list_entry_itor(&list), item2) { tb_trace_i("%lu", item2->data); } // trace tb_trace_i(""); // clear entries tb_single_list_entry_clear(&list); // walk it tb_trace_i("clear: %lu", tb_single_list_entry_size(&list)); tb_for_all_if(tb_demo_entry_t*, item5, tb_single_list_entry_itor(&list), item5) { tb_trace_i("%lu", item5->data); } // exit the list tb_single_list_entry_exit(&list); // trace tb_trace_i(""); return 0; } tbox-1.7.6/src/demo/container/stack.c000066400000000000000000000070131467117505400174620ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_size_t tb_stack_put_and_pop_test() { // init tb_stack_ref_t stack = tb_stack_init(10, tb_element_long()); tb_assert_and_check_return_val(stack, 0); tb_stack_put(stack, (tb_pointer_t)0); tb_stack_put(stack, (tb_pointer_t)1); tb_stack_put(stack, (tb_pointer_t)2); tb_stack_put(stack, (tb_pointer_t)3); tb_stack_put(stack, (tb_pointer_t)4); tb_stack_put(stack, (tb_pointer_t)5); tb_stack_put(stack, (tb_pointer_t)6); tb_stack_put(stack, (tb_pointer_t)7); tb_stack_put(stack, (tb_pointer_t)8); tb_stack_put(stack, (tb_pointer_t)9); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) { tb_stack_pop(stack); tb_stack_put(stack, (tb_pointer_t)0xf); } t = tb_mclock() - t; // time tb_trace_i("tb_stack_put_and_pop(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_stack_size(stack), tb_stack_maxn(stack)); // check tb_assert(tb_stack_size(stack) == 10); tb_assert(tb_stack_head(stack) == (tb_pointer_t)0x0); tb_assert(tb_stack_last(stack) == (tb_pointer_t)0xf); // clear it tb_stack_clear(stack); tb_assert(!tb_stack_size(stack)); // exit tb_stack_exit(stack); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_stack_iterator_next_test() { // init tb_size_t n = 1000000; tb_stack_ref_t stack = tb_stack_init(n, tb_element_long()); tb_assert_and_check_return_val(stack, 0); tb_size_t i; for (i = 0; i < n; i++) tb_stack_put(stack, (tb_pointer_t)0xf); tb_hong_t t = tb_mclock(); tb_for_all (tb_char_t*, item, stack) tb_used(item); t = tb_mclock() - t; // time tb_trace_i("tb_stack_iterator_next(%lu): %lld ms, size: %lu, maxn: %lu", 1000000, t, tb_stack_size(stack), tb_stack_maxn(stack)); // exit tb_stack_exit(stack); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_stack_iterator_prev_test() { // init tb_size_t n = 1000000; tb_stack_ref_t stack = tb_stack_init(n, tb_element_long()); tb_assert_and_check_return_val(stack, 0); tb_size_t i; for (i = 0; i < n; i++) tb_stack_put(stack, (tb_pointer_t)0xf); tb_hong_t t = tb_mclock(); tb_rfor_all (tb_char_t*, item, stack) tb_used(item); t = tb_mclock() - t; // time tb_trace_i("tb_stack_iterator_prev(%lu): %lld ms, size: %lu, maxn: %lu", 1000000, t, tb_stack_size(stack), tb_stack_maxn(stack)); // exit tb_stack_exit(stack); return n / ((tb_uint32_t)(t) + 1); } static tb_void_t tb_stack_perf_test() { tb_size_t score = 0; tb_trace_i("============================================================="); tb_trace_i("put & pop performance:"); score += tb_stack_put_and_pop_test(); tb_trace_i("============================================================="); tb_trace_i("iterator performance:"); score += tb_stack_iterator_next_test(); score += tb_stack_iterator_prev_test(); tb_trace_i("============================================================="); tb_trace_i("score: %lu", score / 100); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_stack_main(tb_int_t argc, tb_char_t** argv) { tb_stack_perf_test(); return 0; } tbox-1.7.6/src/demo/container/vector.c000066400000000000000000000665321467117505400176720ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define TB_VECTOR_GROW_SIZE (256) /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_size_t tb_vector_insert_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_insert_prev(vector, tb_vector_size(vector) >> 1, (tb_pointer_t)0xf); t = tb_mclock() - t; // time tb_trace_i("tb_vector_insert_prev(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xf); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xf); // clear it tb_vector_clear(vector); tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_insert_head_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_insert_head(vector, (tb_pointer_t)0xf); t = tb_mclock() - t; // time tb_trace_i("tb_vector_insert_head(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xf); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xf); // clear it tb_vector_clear(vector); tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_insert_tail_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_insert_tail(vector, (tb_pointer_t)0xf); t = tb_mclock() - t; // time tb_trace_i("tb_vector_insert_tail(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xf); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xf); // clear it tb_vector_clear(vector); tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_ninsert_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); // insert one first tb_vector_insert_head(vector, (tb_pointer_t)0xf); tb_size_t n = 10000; tb_hong_t t = tb_mclock(); tb_vector_ninsert_prev(vector, 1, (tb_pointer_t)0xf, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_ninsert_prev(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n + 1); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xf); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xf); // clear it tb_vector_clear(vector); tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_ninsert_head_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_hong_t t = tb_mclock(); tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_ninsert_head(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xf); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xf); // clear it tb_vector_clear(vector); tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_ninsert_tail_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_hong_t t = tb_mclock(); tb_vector_ninsert_tail(vector, (tb_pointer_t)0xf, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_ninsert_tail(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xf); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xf); // clear it tb_vector_clear(vector); tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_remove_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_remove(vector, tb_vector_size(vector) >> 1); t = tb_mclock() - t; // time tb_trace_i("tb_vector_remove(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_remove_head_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_remove_head(vector); t = tb_mclock() - t; // time tb_trace_i("tb_vector_remove_head(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_remove_last_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_remove_last(vector); t = tb_mclock() - t; // time tb_trace_i("tb_vector_remove_last(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_nremove_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_vector_nremove(vector, tb_iterator_head(vector), n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_nremove(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_nremove_head_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_vector_nremove_head(vector, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_nremove_head(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_nremove_last_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_vector_nremove_last(vector, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_nremove_last(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(!tb_vector_size(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_replace_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); __tb_volatile__ tb_size_t itor = tb_iterator_head(vector); __tb_volatile__ tb_size_t tail = tb_iterator_tail(vector); tb_hong_t t = tb_mclock(); for (; itor != tail; itor = tb_iterator_next(vector, itor)) tb_vector_replace(vector, itor, (tb_pointer_t)0xd); t = tb_mclock() - t; // time tb_trace_i("tb_vector_replace(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xd); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xd); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_replace_head_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_replace_head(vector, (tb_pointer_t)0xd); t = tb_mclock() - t; // time tb_trace_i("tb_vector_replace_head(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xd); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_replace_last_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); __tb_volatile__ tb_size_t i = 0; __tb_volatile__ tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); for (i = 0; i < n; i++) tb_vector_replace_last(vector, (tb_pointer_t)0xd); t = tb_mclock() - t; // time tb_trace_i("tb_vector_replace_last(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xd); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_nreplace_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_vector_nreplace(vector, tb_iterator_head(vector), (tb_pointer_t)0xd, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_nreplace(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xd); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xd); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_nreplace_head_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_vector_nreplace_head(vector, (tb_pointer_t)0xd, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_nreplace_head(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xd); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xd); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_nreplace_last_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_vector_nreplace_last(vector, (tb_pointer_t)0xd, n); t = tb_mclock() - t; // time tb_trace_i("tb_vector_nreplace_last(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // check tb_assert(tb_vector_size(vector) == n); tb_assert(tb_vector_head(vector) == (tb_pointer_t)0xd); tb_assert(tb_vector_last(vector) == (tb_pointer_t)0xd); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_iterator_next_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_for_all (tb_char_t*, item, vector) tb_used(item); t = tb_mclock() - t; // time tb_trace_i("tb_vector_iterator_next(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_size_t tb_vector_iterator_prev_test() { // init tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return_val(vector, 0); tb_size_t n = 10000; tb_vector_ninsert_head(vector, (tb_pointer_t)0xf, n); tb_hong_t t = tb_mclock(); tb_rfor_all (tb_char_t*, item, vector) tb_used(item); t = tb_mclock() - t; // time tb_trace_i("tb_vector_iterator_prev(%lu): %lld ms, size: %lu, maxn: %lu", n, t, tb_vector_size(vector), tb_vector_maxn(vector)); // exit tb_vector_exit(vector); return n / ((tb_uint32_t)(t) + 1); } static tb_void_t tb_vector_int_dump(tb_vector_ref_t vector) { tb_trace_i("tb_int_t size: %lu, maxn: %lu", tb_vector_size(vector), tb_vector_maxn(vector)); tb_for_all (tb_char_t*, item, vector) { tb_trace_i("tb_int_t at[%lu]: %x", item_itor, item); } } static tb_void_t tb_vector_int_test() { tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return(vector); tb_trace_i("============================================================="); tb_trace_i("insert:"); tb_vector_ninsert_head(vector, (tb_pointer_t)0xa, 10); tb_vector_ninsert_tail(vector, (tb_pointer_t)0xf, 10); tb_vector_insert_prev(vector, 10, (tb_pointer_t)0); tb_vector_insert_prev(vector, 10, (tb_pointer_t)1); tb_vector_insert_prev(vector, 10, (tb_pointer_t)2); tb_vector_insert_prev(vector, 10, (tb_pointer_t)3); tb_vector_insert_prev(vector, 10, (tb_pointer_t)4); tb_vector_insert_prev(vector, 10, (tb_pointer_t)5); tb_vector_insert_prev(vector, 10, (tb_pointer_t)6); tb_vector_insert_prev(vector, 10, (tb_pointer_t)7); tb_vector_insert_prev(vector, 10, (tb_pointer_t)8); tb_vector_insert_prev(vector, 10, (tb_pointer_t)9); tb_vector_insert_head(vector, (tb_pointer_t)4); tb_vector_insert_head(vector, (tb_pointer_t)3); tb_vector_insert_head(vector, (tb_pointer_t)2); tb_vector_insert_head(vector, (tb_pointer_t)1); tb_vector_insert_head(vector, (tb_pointer_t)0); tb_vector_insert_tail(vector, (tb_pointer_t)5); tb_vector_insert_tail(vector, (tb_pointer_t)6); tb_vector_insert_tail(vector, (tb_pointer_t)7); tb_vector_insert_tail(vector, (tb_pointer_t)8); tb_vector_insert_tail(vector, (tb_pointer_t)9); tb_vector_int_dump(vector); tb_trace_i("============================================================="); tb_trace_i("remove:"); tb_vector_nremove_head(vector, 5); tb_vector_nremove_last(vector, 5); tb_vector_int_dump(vector); tb_trace_i("============================================================="); tb_trace_i("replace:"); tb_vector_nreplace_head(vector, (tb_pointer_t)0xf, 10); tb_vector_nreplace_last(vector, (tb_pointer_t)0xa, 10); tb_vector_replace_head(vector, 0); tb_vector_replace_last(vector, 0); tb_vector_int_dump(vector); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_vector_clear(vector); tb_vector_int_dump(vector); tb_vector_exit(vector); } static tb_void_t tb_vector_str_dump(tb_vector_ref_t vector) { tb_trace_i("str size: %lu, maxn: %lu", tb_vector_size(vector), tb_vector_maxn(vector)); tb_for_all (tb_char_t*, item, vector) tb_trace_i("str at[%lu]: %s", item_itor, item); } static tb_void_t tb_vector_str_test() { tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_str(tb_true)); tb_assert_and_check_return(vector); tb_trace_i("============================================================="); tb_trace_i("insert:"); tb_vector_ninsert_head(vector, "HHHHHHHHHH", 10); tb_vector_ninsert_tail(vector, "TTTTTTTTTT", 10); tb_vector_insert_prev(vector, 10, "0000000000"); tb_vector_insert_prev(vector, 10, "1111111111"); tb_vector_insert_prev(vector, 10, "2222222222"); tb_vector_insert_prev(vector, 10, "3333333333"); tb_vector_insert_prev(vector, 10, "4444444444"); tb_vector_insert_prev(vector, 10, "5555555555"); tb_vector_insert_prev(vector, 10, "6666666666"); tb_vector_insert_prev(vector, 10, "7777777777"); tb_vector_insert_prev(vector, 10, "8888888888"); tb_vector_insert_prev(vector, 10, "9999999999"); tb_vector_insert_head(vector, "4444444444"); tb_vector_insert_head(vector, "3333333333"); tb_vector_insert_head(vector, "2222222222"); tb_vector_insert_head(vector, "1111111111"); tb_vector_insert_head(vector, "0000000000"); tb_vector_insert_tail(vector, "5555555555"); tb_vector_insert_tail(vector, "6666666666"); tb_vector_insert_tail(vector, "7777777777"); tb_vector_insert_tail(vector, "8888888888"); tb_vector_insert_tail(vector, "9999999999"); tb_vector_str_dump(vector); tb_trace_i("============================================================="); tb_trace_i("remove:"); tb_vector_nremove_head(vector, 5); tb_vector_nremove_last(vector, 5); tb_vector_str_dump(vector); tb_trace_i("============================================================="); tb_trace_i("replace:"); tb_vector_nreplace_head(vector, "TTTTTTTTTT", 10); tb_vector_nreplace_last(vector, "HHHHHHHHHH", 10); tb_vector_replace_head(vector, "OOOOOOOOOO"); tb_vector_replace_last(vector, "OOOOOOOOOO"); tb_vector_str_dump(vector); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_vector_clear(vector); tb_vector_str_dump(vector); tb_vector_exit(vector); } static tb_void_t tb_vector_mem_dump(tb_vector_ref_t vector) { tb_trace_i("ifm size: %lu, maxn: %lu", tb_vector_size(vector), tb_vector_maxn(vector)); tb_for_all (tb_char_t*, item, vector) { tb_trace_i("ifm at[%lu]: %s", item_itor, item); } } static tb_void_t tb_vector_mem_free(tb_element_ref_t element, tb_pointer_t buff) { tb_trace_i("ifm free: %s, priv: %s", buff, element->priv); } static tb_void_t tb_vector_mem_test() { tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_mem(11, tb_vector_mem_free, "ifm")); tb_assert_and_check_return(vector); tb_trace_i("============================================================="); tb_trace_i("insert:"); tb_vector_ninsert_head(vector, "HHHHHHHHHH", 10); tb_vector_ninsert_tail(vector, "TTTTTTTTTT", 10); tb_vector_insert_prev(vector, 10, "0000000000"); tb_vector_insert_prev(vector, 10, "1111111111"); tb_vector_insert_prev(vector, 10, "2222222222"); tb_vector_insert_prev(vector, 10, "3333333333"); tb_vector_insert_prev(vector, 10, "4444444444"); tb_vector_insert_prev(vector, 10, "5555555555"); tb_vector_insert_prev(vector, 10, "6666666666"); tb_vector_insert_prev(vector, 10, "7777777777"); tb_vector_insert_prev(vector, 10, "8888888888"); tb_vector_insert_prev(vector, 10, "9999999999"); tb_vector_insert_head(vector, "4444444444"); tb_vector_insert_head(vector, "3333333333"); tb_vector_insert_head(vector, "2222222222"); tb_vector_insert_head(vector, "1111111111"); tb_vector_insert_head(vector, "0000000000"); tb_vector_insert_tail(vector, "5555555555"); tb_vector_insert_tail(vector, "6666666666"); tb_vector_insert_tail(vector, "7777777777"); tb_vector_insert_tail(vector, "8888888888"); tb_vector_insert_tail(vector, "9999999999"); tb_vector_mem_dump(vector); tb_trace_i("============================================================="); tb_trace_i("remove:"); tb_vector_nremove_head(vector, 5); tb_vector_nremove_last(vector, 5); tb_vector_mem_dump(vector); tb_trace_i("============================================================="); tb_trace_i("replace:"); tb_vector_nreplace_head(vector, "TTTTTTTTTT", 10); tb_vector_nreplace_last(vector, "HHHHHHHHHH", 10); tb_vector_replace_head(vector, "OOOOOOOOOO"); tb_vector_replace_last(vector, "OOOOOOOOOO"); tb_vector_mem_dump(vector); tb_trace_i("============================================================="); tb_trace_i("clear:"); tb_vector_clear(vector); tb_vector_mem_dump(vector); tb_vector_exit(vector); } static tb_void_t tb_vector_perf_test() { tb_size_t score = 0; tb_trace_i("============================================================="); tb_trace_i("insert performance:"); score += tb_vector_insert_test(); score += tb_vector_insert_head_test(); score += tb_vector_insert_tail_test(); score += tb_vector_ninsert_test(); score += tb_vector_ninsert_head_test(); score += tb_vector_ninsert_tail_test(); tb_trace_i("============================================================="); tb_trace_i("remove performance:"); score += tb_vector_remove_test(); score += tb_vector_remove_head_test(); score += tb_vector_remove_last_test(); score += tb_vector_nremove_test(); score += tb_vector_nremove_head_test(); score += tb_vector_nremove_last_test(); tb_trace_i("============================================================="); tb_trace_i("replace performance:"); score += tb_vector_replace_test(); score += tb_vector_replace_head_test(); score += tb_vector_replace_last_test(); score += tb_vector_nreplace_test(); score += tb_vector_nreplace_head_test(); score += tb_vector_nreplace_last_test(); tb_trace_i("============================================================="); tb_trace_i("iterator performance:"); score += tb_vector_iterator_next_test(); score += tb_vector_iterator_prev_test(); tb_trace_i("============================================================="); tb_trace_i("score: %lu", score / 100); } static tb_void_t tb_vector_test_itor_perf() { // init vector tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_size()); tb_assert_and_check_return(vector); // reset random tb_random_reset(tb_true); // add items __tb_volatile__ tb_size_t n = 10000; while (n--) tb_vector_insert_tail(vector, (tb_pointer_t)(tb_size_t)tb_random_value()); // done tb_hong_t t = tb_mclock(); __tb_volatile__ tb_hize_t test[2] = {0}; __tb_volatile__ tb_size_t itor = tb_iterator_head(vector); for (; itor != tb_iterator_tail(vector); ) { __tb_volatile__ tb_size_t item = (tb_size_t)tb_iterator_item(vector, itor); if (!(((tb_size_t)item >> 25) & 0x1)) { // remove, hack: the itor of the same item is mutable tb_vector_remove(vector, itor); // continue continue ; } else { test[0] += (tb_size_t)item; test[1]++; } itor = tb_iterator_next(vector, itor); } t = tb_mclock() - t; tb_trace_i("item: %llx, size: %llu ?= %u, time: %lld", test[0], test[1], tb_vector_size(vector), t); // exit tb_vector_exit(vector); } static tb_bool_t tb_vector_test_walk_item(tb_iterator_ref_t iterator, tb_cpointer_t item, tb_cpointer_t value) { // done tb_hize_t* test = (tb_hize_t*)value; tb_size_t i = (tb_size_t)item; tb_bool_t ok = tb_false; if (!((i >> 25) & 0x1)) ok = tb_true; else { test[0] += i; test[1]++; } // ok? return ok; } static tb_void_t tb_vector_test_walk_perf() { // init vector tb_vector_ref_t vector = tb_vector_init(TB_VECTOR_GROW_SIZE, tb_element_long()); tb_assert_and_check_return(vector); // reset random tb_random_reset(tb_true); // add items __tb_volatile__ tb_size_t n = 10000; while (n--) tb_vector_insert_tail(vector, (tb_pointer_t)(tb_size_t)tb_random_value()); // done tb_hong_t t = tb_mclock(); __tb_volatile__ tb_hize_t test[2] = {0}; tb_remove_if(vector, tb_vector_test_walk_item, (tb_pointer_t)test); t = tb_mclock() - t; // trace tb_trace_i("item: %llx, size: %llu ?= %u, time: %lld", test[0], test[1], tb_vector_size(vector), t); // exit tb_vector_exit(vector); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_container_vector_main(tb_int_t argc, tb_char_t** argv) { #if 1 tb_vector_int_test(); tb_vector_str_test(); tb_vector_mem_test(); #endif #if 1 tb_vector_perf_test(); #endif #if 1 tb_vector_test_itor_perf(); tb_vector_test_walk_perf(); #endif return 0; } tbox-1.7.6/src/demo/coroutine/000077500000000000000000000000001467117505400162355ustar00rootroot00000000000000tbox-1.7.6/src/demo/coroutine/channel.c000066400000000000000000000106361467117505400200170ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the switch count #define COUNT (10000000) /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_channel_test_send(tb_cpointer_t priv) { // check tb_co_channel_ref_t channel = (tb_co_channel_ref_t)priv; // loop tb_size_t count = 10; while (count--) { // trace tb_trace_i("[coroutine: %p]: send: %lu", tb_coroutine_self(), count); // send data tb_co_channel_send(channel, (tb_cpointer_t)count); // trace tb_trace_i("[coroutine: %p]: send: %lu ok", tb_coroutine_self(), count); } } static tb_void_t tb_demo_coroutine_channel_test_recv(tb_cpointer_t priv) { // check tb_co_channel_ref_t channel = (tb_co_channel_ref_t)priv; // loop tb_size_t count = 10; while (count--) { // trace tb_trace_i("[coroutine: %p]: recv: ..", tb_coroutine_self()); // recv tb_size_t data = (tb_size_t)tb_co_channel_recv(channel); // trace tb_trace_i("[coroutine: %p]: recv: %lu ok", tb_coroutine_self(), data); } } static tb_void_t tb_demo_coroutine_channel_test(tb_size_t size) { // trace tb_trace_i("test: %lu", size); // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // init channel tb_co_channel_ref_t channel = tb_co_channel_init(size, tb_null, 0); tb_assert(channel); // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_channel_test_send, channel, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_channel_test_send, channel, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_channel_test_send, channel, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_channel_test_recv, channel, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_channel_test_recv, channel, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_channel_test_recv, channel, 0); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit channel tb_co_channel_exit(channel); // exit scheduler tb_co_scheduler_exit(scheduler); } } static tb_void_t tb_demo_coroutine_channel_perf_send(tb_cpointer_t priv) { // check tb_co_channel_ref_t channel = (tb_co_channel_ref_t)priv; // loop tb_size_t count = COUNT; while (count--) tb_co_channel_send(channel, (tb_cpointer_t)count); } static tb_void_t tb_demo_coroutine_channel_perf_recv(tb_cpointer_t priv) { // check tb_co_channel_ref_t channel = (tb_co_channel_ref_t)priv; // loop tb_size_t count = COUNT; while (count--) tb_co_channel_recv(channel); } static tb_void_t tb_demo_coroutine_channel_perf(tb_size_t size) { // trace tb_trace_i("perf: %lu", size); // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // init channel tb_co_channel_ref_t channel = tb_co_channel_init(size, tb_null, 0); tb_assert(channel); // start coroutine tb_coroutine_start(scheduler, tb_demo_coroutine_channel_perf_send, channel, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_channel_perf_recv, channel, 0); // init the start time tb_hong_t startime = tb_mclock(); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // computing time tb_hong_t duration = tb_mclock() - startime; // exit channel tb_co_channel_exit(channel); // trace tb_trace_i("%d passes in %lld ms, %lld passes per second", COUNT, duration, (((tb_hong_t)1000 * COUNT) / duration)); // exit scheduler tb_co_scheduler_exit(scheduler); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_channel_main(tb_int_t argc, tb_char_t** argv) { tb_demo_coroutine_channel_test(0); tb_demo_coroutine_channel_test(1); tb_demo_coroutine_channel_test(5); tb_demo_coroutine_channel_perf(0); tb_demo_coroutine_channel_perf(1); tb_demo_coroutine_channel_perf(10); return 0; } tbox-1.7.6/src/demo/coroutine/dns.c000066400000000000000000000025671467117505400171770ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_dns(tb_cpointer_t priv) { tb_ipaddr_t addr; tb_hong_t time = tb_mclock(); tb_char_t const* name = (tb_char_t const*)priv; if (tb_dns_looker_done(name, &addr)) { time = tb_mclock() - time; tb_trace_i("lookup: %s => %{ipaddr}, %lld ms", name, &addr, time); } else tb_trace_i("lookup: %s failed", name); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_dns_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argc >= 2 && argv[1], -1); // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start dns tb_size_t n = argv[2]? (tb_size_t)tb_atoi(argv[2]) : 10; while (n--) { // start it tb_coroutine_start(scheduler, tb_demo_coroutine_dns, argv[1], 0); } // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit scheduler tb_co_scheduler_exit(scheduler); } // end return 0; } tbox-1.7.6/src/demo/coroutine/echo_client.c000066400000000000000000000057721467117505400206700ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // port #define TB_DEMO_PORT (9001) // timeout #define TB_DEMO_TIMEOUT (-1) /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_echo(tb_cpointer_t priv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // init address tb_ipaddr_t addr; tb_ipaddr_set(&addr, "127.0.0.1", TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); // trace tb_trace_i("connecting(%p): %{ipaddr} ..", sock, &addr); // connect socket tb_long_t ok; while (!(ok = tb_socket_connect(sock, &addr))) { // wait it if (tb_socket_wait(sock, TB_SOCKET_EVENT_CONN, TB_DEMO_TIMEOUT) <= 0) break; } // connect ok? tb_check_break(ok > 0); // loop tb_byte_t data[8192] = {0}; tb_long_t count = (tb_long_t)priv; while (count--) { // send data if (tb_socket_bsend(sock, (tb_byte_t const*)"hello world..", 13)) { // recv data if (!tb_socket_brecv(sock, data, 13)) { // error tb_trace_e("send error!"); break; } } else break; } // trace tb_trace_d("send(%p): %s %s", sock, data, count <= 0? "ok" : "failed"); } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_echo_client_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argc >= 1, -1); // the coroutines count tb_size_t count = argc > 1? tb_atoi(argv[1]) : 100; // the request count tb_size_t reqt_count = argc > 2? tb_atoi(argv[2]) : 10000; // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start echo tb_size_t i = 0; for (i = 0; i < count; i++) tb_coroutine_start(scheduler, tb_demo_coroutine_echo, (tb_cpointer_t)reqt_count, 0); // start time tb_hong_t startime = tb_mclock(); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // compute the spent time tb_hong_t spent = tb_mclock() - startime; // trace tb_trace_i("echo: clients: %lu, request: %lu, spent: %lld ms", count, reqt_count, spent); // exit scheduler tb_co_scheduler_exit(scheduler); } // end return 0; } tbox-1.7.6/src/demo/coroutine/echo_server.c000066400000000000000000000053071467117505400207120ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // port #define TB_DEMO_PORT (9001) // timeout #define TB_DEMO_TIMEOUT (-1) /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_client(tb_cpointer_t priv) { // check tb_socket_ref_t sock = (tb_socket_ref_t)priv; tb_assert_and_check_return(sock); // loop tb_byte_t data[8192] = {0}; tb_size_t size = 13; while (1) { // recv data if (tb_socket_brecv(sock, data, size)) { // send data if (!tb_socket_bsend(sock, data, size)) { // error tb_trace_e("send error!"); break; } } else break; } // trace tb_trace_d("echo: %s", data); // exit socket tb_socket_exit(sock); } static tb_void_t tb_demo_coroutine_listen(tb_cpointer_t priv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // bind socket tb_ipaddr_t addr; tb_ipaddr_set(&addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); if (!tb_socket_bind(sock, &addr)) break; // listen socket if (!tb_socket_listen(sock, 1000)) break; // trace tb_trace_i("listening .."); // accept client sockets tb_socket_ref_t client = tb_null; while (1) { // accept and start client connection if ((client = tb_socket_accept(sock, tb_null))) { if (!tb_coroutine_start(tb_null, tb_demo_coroutine_client, client, 0)) break; } else if (tb_socket_wait(sock, TB_SOCKET_EVENT_ACPT, TB_DEMO_TIMEOUT) < 0) break; } } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_echo_server_main(tb_int_t argc, tb_char_t** argv) { // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start listening tb_coroutine_start(scheduler, tb_demo_coroutine_listen, tb_null, 0); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit scheduler tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/file_client.c000066400000000000000000000127011467117505400206570ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_client" #define TB_TRACE_MODULE_DEBUG (1) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // port #define TB_DEMO_PORT (9090) // timeout #define TB_DEMO_TIMEOUT (-1) // eanble conn/recv coroutine #define TB_DEMO_CONN_RECV (0) /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ #if TB_DEMO_CONN_RECV static tb_void_t tb_demo_coroutine_recv(tb_cpointer_t priv) { // check tb_socket_ref_t sock = (tb_socket_ref_t)priv; tb_assert_and_check_return(sock); // trace tb_trace_d("[%p]: recving ..", sock); // recv data tb_byte_t data[8192]; tb_hize_t recv = 0; tb_long_t wait = 0; tb_hong_t time = tb_mclock(); while (1) { // read it tb_long_t real = tb_socket_recv(sock, data, sizeof(data)); // trace tb_trace_d("[%p]: recv: %ld, total: %lu", sock, real, recv + (real > 0? real : 0)); // has data? if (real > 0) { recv += real; wait = 0; } // no data? wait it else if (!real && !wait) { // wait it wait = tb_socket_wait(sock, TB_SOCKET_EVENT_RECV, TB_DEMO_TIMEOUT); tb_assert_and_check_break(wait >= 0); } // failed or end? else break; } // trace tb_trace_i("[%p]: recv %llu bytes %lld ms", sock, recv, tb_mclock() - time); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; } static tb_void_t tb_demo_coroutine_pull(tb_cpointer_t priv) { tb_long_t ok = -1; tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // init address tb_ipaddr_t addr; tb_ipaddr_set(&addr, "127.0.0.1", TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); // trace tb_trace_d("[%p]: connecting %{ipaddr} ..", sock, &addr); // connect socket while (!(ok = tb_socket_connect(sock, &addr))) { // wait it if (tb_socket_wait(sock, TB_SOCKET_EVENT_CONN, TB_DEMO_TIMEOUT) <= 0) break; } // connect ok? tb_check_break(ok > 0); // start recv coroutine tb_coroutine_start(tb_co_scheduler_self(), tb_demo_coroutine_recv, sock, 0); } while (0); // failed? if (ok <= 0) { if (sock) tb_socket_exit(sock); sock = tb_null; } } #else static tb_void_t tb_demo_coroutine_pull(tb_cpointer_t priv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // init address tb_ipaddr_t addr; tb_ipaddr_set(&addr, "127.0.0.1", TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); // trace tb_trace_d("[%p]: connecting %{ipaddr} ..", sock, &addr); // connect socket tb_long_t ok; while (!(ok = tb_socket_connect(sock, &addr))) { // wait it if (tb_socket_wait(sock, TB_SOCKET_EVENT_CONN, TB_DEMO_TIMEOUT) <= 0) break; } // connect ok? tb_check_break(ok > 0); // trace tb_trace_d("[%p]: recving ..", sock); // recv data tb_byte_t data[8192]; tb_hize_t recv = 0; tb_long_t wait = 0; tb_hong_t time = tb_mclock(); while (1) { // read it tb_long_t real = tb_socket_recv(sock, data, sizeof(data)); // trace tb_trace_d("[%p]: recv: %ld, total: %lu", sock, real, recv + (real > 0? real : 0)); // has data? if (real > 0) { recv += real; wait = 0; } // no data? wait it else if (!real && !wait) { // wait it wait = tb_socket_wait(sock, TB_SOCKET_EVENT_RECV, TB_DEMO_TIMEOUT); tb_assert_and_check_break(wait >= 0); } // failed or end? else break; } // trace tb_trace_i("[%p]: recv %llu bytes %lld ms", sock, recv, tb_mclock() - time); } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; } #endif /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_file_client_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argc == 2 && argv[1], -1); // the coroutines count tb_size_t count = tb_atoi(argv[1]); // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start file tb_size_t i = 0; for (i = 0; i < count; i++) { // start it tb_coroutine_start(scheduler, tb_demo_coroutine_pull, tb_null, 0); } // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit scheduler tb_co_scheduler_exit(scheduler); } // end return 0; } tbox-1.7.6/src/demo/coroutine/file_server.c000066400000000000000000000101051467117505400207030ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "file_server" #define TB_TRACE_MODULE_DEBUG (1) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // port #define TB_DEMO_PORT (9090) // timeout #define TB_DEMO_TIMEOUT (-1) /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // the file path static tb_char_t g_filepath[TB_PATH_MAXN]; /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_client(tb_cpointer_t priv) { // check tb_socket_ref_t sock = (tb_socket_ref_t)priv; tb_assert_and_check_return(sock); // trace tb_trace_d("[%p]: sending %s ..", sock, g_filepath); // init file tb_file_ref_t file = tb_file_init(g_filepath, TB_FILE_MODE_RO); tb_assert_and_check_return(file); // send data tb_hize_t send = 0; tb_hize_t size = tb_file_size(file); tb_long_t wait = 0; tb_hong_t time = tb_mclock(); while (send < size) { // send it tb_hong_t real = tb_socket_sendf(sock, file, send, size - send); // trace tb_trace_d("[%p]: send: %lld, total: %llu", sock, real, send + (real > 0? real : 0)); // has data? if (real > 0) { send += real; wait = 0; } // no data? wait it else if (!real && !wait) { // wait it wait = tb_socket_wait(sock, TB_SOCKET_EVENT_SEND, TB_DEMO_TIMEOUT); tb_assert_and_check_break(wait >= 0); } // failed or end? else break; } // trace tb_trace_i("[%p]: send: %lld bytes %lld ms", sock, send, tb_mclock() - time); // exit file tb_file_exit(file); // exit socket tb_socket_exit(sock); } static tb_void_t tb_demo_coroutine_listen(tb_cpointer_t priv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // bind socket tb_ipaddr_t addr; tb_ipaddr_set(&addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); if (!tb_socket_bind(sock, &addr)) break; // listen socket if (!tb_socket_listen(sock, 1000)) break; // trace tb_trace_i("listening .."); // accept client sockets tb_size_t count = 0; tb_socket_ref_t client = tb_null; while (1) { // accept and start client connection if ((client = tb_socket_accept(sock, tb_null))) { if (!tb_coroutine_start(tb_null, tb_demo_coroutine_client, client, 0)) break; count++; } else if (tb_socket_wait(sock, TB_SOCKET_EVENT_ACPT, -1) <= 0) break; } // trace tb_trace_i("listened %lu", count); } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_file_server_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argc == 2 && argv[1], -1); // the file path tb_char_t const* filepath = argv[1]; tb_assert_and_check_return_val(filepath, -1); // save the file path tb_strlcpy(g_filepath, filepath, sizeof(g_filepath)); // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start listening tb_coroutine_start(scheduler, tb_demo_coroutine_listen, tb_null, 0); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit scheduler tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/fwatcher.c000066400000000000000000000034601467117505400202070ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t tb_demo_coroutine_watch(tb_cpointer_t priv) { tb_char_t const* path = (tb_char_t const*)priv; tb_fwatcher_ref_t fwatcher = tb_fwatcher_init(); if (fwatcher) { tb_trace_i("watching %s", path); if (tb_fwatcher_add(fwatcher, path, tb_true)) { tb_bool_t eof = tb_false; tb_fwatcher_event_t event; while (!eof && tb_fwatcher_wait(fwatcher, &event, -1) >= 0) { tb_char_t const* status = event.event == TB_FWATCHER_EVENT_CREATE? "created" : (event.event == TB_FWATCHER_EVENT_MODIFY? "modified" : "deleted"); tb_trace_i("watch: %s %s", event.filepath, status); if (tb_strstr(event.filepath, "eof")) eof = tb_true; } } tb_fwatcher_exit(fwatcher); } } static tb_void_t tb_demo_coroutine_sleep(tb_cpointer_t priv) { while (1) { tb_trace_i("sleep .."); tb_sleep(1); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_fwatcher_main(tb_int_t argc, tb_char_t** argv) { tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_watch, argv[1], 0); tb_coroutine_start(scheduler, tb_demo_coroutine_sleep, tb_null, 0); // do loop tb_co_scheduler_loop(scheduler, tb_true); tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/http_server.c000066400000000000000000000350611467117505400207530ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the port #define TB_DEMO_PORT (8080) // the timeout #define TB_DEMO_TIMEOUT (-1) // the cpu-core count #define TB_DEMO_CPU (1) // the stack size #define TB_DEMO_STACKSIZE (8192 << 2) /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the http session type typedef struct __tb_demo_http_session_t { // the socket tb_socket_ref_t sock; // the http code tb_size_t code; // the http method tb_size_t method; // the content size tb_hize_t content_size; // is keep-alive? tb_bool_t keep_alive; // the file tb_file_ref_t file; // the data buffer tb_byte_t data[8192]; // the resource path tb_char_t path[1024]; // the line buffer tb_char_t line[1024]; // the line size tb_size_t line_size; // the line index tb_size_t line_index; }tb_demo_http_session_t, *tb_demo_http_session_ref_t; /* ////////////////////////////////////////////////////////////////////////////////////// * globals */ // the root directory static tb_char_t g_rootdir[TB_PATH_MAXN]; // only send data for testing? static tb_bool_t g_onlydata = tb_false; /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_bool_t tb_demo_http_session_init(tb_demo_http_session_ref_t session, tb_socket_ref_t sock) { // check tb_assert(session && sock); // init session->sock = sock; session->file = tb_null; session->line_size = 0; session->line_index = 0; session->keep_alive = tb_false; session->code = TB_HTTP_CODE_OK; session->method = TB_HTTP_METHOD_GET; session->content_size = 0; // ok return tb_true; } static tb_void_t tb_demo_http_session_exit(tb_demo_http_session_ref_t session) { // check tb_assert(session); // exit socket if (session->sock) tb_socket_exit(session->sock); session->sock = tb_null; // exit file if (session->file) tb_file_exit(session->file); session->file = tb_null; } static tb_bool_t tb_demo_http_session_data_send(tb_socket_ref_t sock, tb_byte_t* data, tb_size_t size) { // check tb_assert_and_check_return_val(sock && data && size, tb_false); // send data tb_size_t send = 0; tb_long_t wait = 0; while (send < size) { // send it tb_long_t real = tb_socket_send(sock, data + send, size - send); // has data? if (real > 0) { send += real; wait = 0; } // no data? wait it else if (!real && !wait) { // wait it wait = tb_socket_wait(sock, TB_SOCKET_EVENT_SEND, TB_DEMO_TIMEOUT); tb_assert_and_check_break(wait >= 0); } // failed or end? else break; } // ok? return send == size; } static tb_bool_t tb_demo_http_session_file_send(tb_socket_ref_t sock, tb_file_ref_t file) { // check tb_assert_and_check_return_val(sock && file, tb_false); // send data tb_hize_t send = 0; tb_hize_t size = tb_file_size(file); tb_long_t wait = 0; while (send < size) { // send it tb_hong_t real = tb_socket_sendf(sock, file, send, size - send); // has data? if (real > 0) { send += real; wait = 0; } // no data? wait it else if (!real && !wait) { // wait it wait = tb_socket_wait(sock, TB_SOCKET_EVENT_SEND, TB_DEMO_TIMEOUT); tb_assert_and_check_break(wait >= 0); } // failed or end? else break; } // ok? return send == size; } static tb_char_t const* tb_demo_http_session_code_cstr(tb_size_t code) { // done tb_char_t const* cstr = tb_null; switch (code) { case TB_HTTP_CODE_OK: cstr = "OK"; break; case TB_HTTP_CODE_BAD_REQUEST: cstr = "Bad Request"; break; case TB_HTTP_CODE_NOT_FOUND: cstr = "Not Found"; break; case TB_HTTP_CODE_NOT_IMPLEMENTED: cstr = "Not Implemented"; break; case TB_HTTP_CODE_NOT_MODIFIED: cstr = "Not Modified"; break; case TB_HTTP_CODE_INTERNAL_SERVER_ERROR: cstr = "Internal Server Error"; break; default: break; } // check tb_assert(cstr); // ok? return cstr; } static tb_bool_t tb_demo_http_session_resp_send(tb_demo_http_session_ref_t session, tb_char_t const* cstr) { // check tb_assert_and_check_return_val(session && session->sock, tb_false); // make the response header tb_long_t size = tb_snprintf( (tb_char_t*)session->data , sizeof(session->data) , "HTTP/1.1 %lu %s\r\n" "Server: %s\r\n" "Content-Type: text/html\r\n" "Content-Length: %llu\r\n" "Connection: %s\r\n" "\r\n" "%s" , session->code , tb_demo_http_session_code_cstr(session->code) , TB_VERSION_SHORT_STRING , session->file? tb_file_size(session->file) : (cstr? tb_strlen(cstr) : 0) , session->keep_alive? "keep-alive" : "close" , cstr? cstr : ""); tb_assert_and_check_return_val(size > 0, tb_false); // end session->data[size] = 0; // send the response header if (!tb_demo_http_session_data_send(session->sock, session->data, size)) return tb_false; // send the response file if exists if (session->file && !tb_demo_http_session_file_send(session->sock, session->file)) return tb_false; // ok return tb_true; } static tb_void_t tb_demo_http_session_head_parse(tb_demo_http_session_ref_t session) { // check tb_assert_and_check_return(session); // the first line? tb_char_t const* p = session->line; if (!session->line_index) { // parse get if (!tb_strnicmp(p, "GET", 3)) { session->code = TB_HTTP_CODE_OK; session->method = TB_HTTP_METHOD_GET; p += 3; } // parse post else if (!tb_strnicmp(p, "POST", 4)) { session->code = TB_HTTP_CODE_NOT_IMPLEMENTED; session->method = TB_HTTP_METHOD_POST; p += 4; } // other method is not implemented else session->code = TB_HTTP_CODE_NOT_IMPLEMENTED; // get or post? parse the path if ( session->method == TB_HTTP_METHOD_GET || session->method == TB_HTTP_METHOD_POST) { // skip space while (*p && tb_isspace(*p)) p++; // append path tb_size_t i = 0; while (*p && !tb_isspace(*p) && i < sizeof(session->path) - 1) session->path[i++] = *p++; session->path[i] = '\0'; } } // key: value? else { // seek to value while (*p && *p != ':') p++; tb_assert_and_check_return(*p); p++; while (*p && tb_isspace(*p)) p++; // no value tb_check_return(*p); // parse content-length if (!tb_strnicmp(session->line, "Content-Length", 14)) session->content_size = tb_stou64(p); // parse connection else if (!tb_strnicmp(session->line, "Connection", 10)) session->keep_alive = !tb_stricmp(p, "keep-alive"); // parse range else if (!tb_strnicmp(session->line, "Range", 5)) session->code = TB_HTTP_CODE_NOT_IMPLEMENTED; } } static tb_long_t tb_demo_http_session_head_line(tb_demo_http_session_ref_t session, tb_byte_t const* data, tb_size_t size) { // check tb_assert_and_check_return_val(session && data && size, -1); // done tb_long_t ok = 0; do { // done tb_char_t ch = '\0'; tb_char_t const* p = (tb_char_t const*)data; tb_char_t const* e = p + size; while (p < e) { // the char ch = *p++; // error end? if (!ch) { ok = -1; break; } // append char to line if (ch != '\n') session->line[session->line_size++] = ch; // is line end? else { // line end? strip '\r\n' if (session->line_size && session->line[session->line_size - 1] == '\r') { session->line_size--; session->line[session->line_size] = '\0'; } // trace tb_trace_d("head: %s", session->line); // end? if (!session->line_size) { // ok ok = 1; break; } // parse the header line tb_demo_http_session_head_parse(session); // clear line session->line_size = 0; // update line index session->line_index++; } } } while (0); // ok? return ok; } static tb_bool_t tb_demo_http_session_head_recv(tb_demo_http_session_ref_t session) { // check tb_assert_and_check_return_val(session && session->sock, tb_false); // read data tb_long_t wait = 0; tb_long_t ok = 0; while (!ok) { // read it tb_long_t real = tb_socket_recv(session->sock, session->data, sizeof(session->data)); // has data? if (real > 0) { // get the header line ok = tb_demo_http_session_head_line(session, session->data, real); // clear wait events wait = 0; } // no data? wait it else if (!real && !wait) { // wait it wait = tb_socket_wait(session->sock, TB_SOCKET_EVENT_RECV, TB_DEMO_TIMEOUT); tb_assert_and_check_break(wait >= 0); } // failed or end? else break; } // ok? return ok > 0; } static tb_void_t tb_demo_coroutine_client(tb_cpointer_t priv) { // check tb_socket_ref_t sock = (tb_socket_ref_t)priv; tb_assert_and_check_return(sock); // done tb_demo_http_session_t session; do { // init session if (!tb_demo_http_session_init(&session, sock)) break; // read the request header if (!tb_demo_http_session_head_recv(&session)) break; // trace tb_trace_d("path: %s", session.path); // get file or data? tb_char_t const* data = tb_null; if (session.method == TB_HTTP_METHOD_GET) { // only send data? if (g_onlydata) data = g_rootdir; else { // make full path tb_long_t size = tb_snprintf((tb_char_t*)session.data, sizeof(session.data), "%s%s%s", g_rootdir, session.path[0] != '/'? "/" : "", session.path); if (size > 0) session.data[size] = 0; // init file session.file = tb_file_init((tb_char_t*)session.data, TB_FILE_MODE_RO); // not found? if (!session.file) session.code = TB_HTTP_CODE_NOT_FOUND; } } // send the response if (!tb_demo_http_session_resp_send(&session, data)) break; // exit file if (session.file) tb_file_exit(session.file); session.file = tb_null; // trace tb_trace_d("ok!"); } while (session.keep_alive); // exit session tb_demo_http_session_exit(&session); } static tb_void_t tb_demo_coroutine_listen(tb_cpointer_t priv) { // TODO: fix thundering herd issues tb_size_t count = 0; tb_socket_ref_t client = tb_null; tb_socket_ref_t sock = (tb_socket_ref_t)priv; while (1) { // accept and start client connection if ((client = tb_socket_accept(sock, tb_null))) { if (!tb_coroutine_start(tb_null, tb_demo_coroutine_client, client, TB_DEMO_STACKSIZE)) break; count++; } else if (tb_socket_wait(sock, TB_SOCKET_EVENT_ACPT, -1) <= 0) break; } // trace tb_trace_i("[%#x]: listened %lu", tb_thread_self(), count); } static tb_int_t tb_demo_coroutine_worker(tb_cpointer_t priv) { // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_listen, priv, 0); // run scheduler, enable exclusive mode if be only one cpu tb_co_scheduler_loop(scheduler, TB_DEMO_CPU == 1); // exit scheduler tb_co_scheduler_exit(scheduler); } return 0; } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_http_server_main(tb_int_t argc, tb_char_t** argv) { // done tb_socket_ref_t sock = tb_null; do { // init socket sock = tb_socket_init(TB_SOCKET_TYPE_TCP, TB_IPADDR_FAMILY_IPV4); tb_assert_and_check_break(sock); // bind socket tb_ipaddr_t addr; tb_ipaddr_set(&addr, tb_null, TB_DEMO_PORT, TB_IPADDR_FAMILY_IPV4); if (!tb_socket_bind(sock, &addr)) break; // listen socket if (!tb_socket_listen(sock, 1000)) break; // init the root directory if (argv[1]) tb_strlcpy(g_rootdir, argv[1], sizeof(g_rootdir)); else tb_directory_current(g_rootdir, sizeof(g_rootdir)); // only data? if (!tb_file_info(g_rootdir, tb_null)) g_onlydata = tb_true; // trace tb_trace_i("%s: %s", g_onlydata? "data" : "rootdir", g_rootdir); #if TB_DEMO_CPU > 1 // start workers for multi-threads tb_size_t count = TB_DEMO_CPU - 1; while (count--) tb_thread_init(tb_null, tb_demo_coroutine_worker, sock, 0); #endif // start worker tb_demo_coroutine_worker(sock); } while (0); // exit socket if (sock) tb_socket_exit(sock); sock = tb_null; // ok return 0; } tbox-1.7.6/src/demo/coroutine/lock.c000066400000000000000000000035021467117505400173310ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_lock_test_func(tb_cpointer_t priv) { // check tb_co_lock_ref_t lock = (tb_co_lock_ref_t)priv; tb_assert_and_check_return(lock); // loop tb_size_t count = 10; while (count--) { // enter lock tb_co_lock_enter(lock); // trace tb_trace_i("[coroutine: %p]: enter", tb_coroutine_self()); // wait some time tb_msleep(1000); // trace tb_trace_i("[coroutine: %p]: leave", tb_coroutine_self()); // leave lock tb_co_lock_leave(lock); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_lock_main(tb_int_t argc, tb_char_t** argv) { // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // init lock tb_co_lock_ref_t lock = tb_co_lock_init(); tb_assert(lock); // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_lock_test_func, lock, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_lock_test_func, lock, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_lock_test_func, lock, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_lock_test_func, lock, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_lock_test_func, lock, 0); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit lock tb_co_lock_exit(lock); // exit scheduler tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/nest.c000066400000000000000000000030361467117505400173540ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_nest_next(tb_size_t start, tb_size_t end) { // loop for (; start < end; start++) { // trace tb_trace_i("[coroutine: %p]: %lu", tb_coroutine_self(), start); // yield tb_coroutine_yield(); } } static tb_void_t tb_demo_coroutine_nest_func(tb_cpointer_t priv) { // loop tb_size_t count = (tb_size_t)priv; while (count--) { // trace tb_trace_i("[coroutine: %p]: %lu", tb_coroutine_self(), count); // call next level function tb_demo_coroutine_nest_next(count * 10, count * 10 + 5); // yield tb_coroutine_yield(); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_nest_main(tb_int_t argc, tb_char_t** argv) { // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_nest_func, (tb_cpointer_t)10, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_nest_func, (tb_cpointer_t)10, 0); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit scheduler tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/ping.c000066400000000000000000000157541467117505400173520ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define TB_ICMP_ECHOREPLY (0) #define TB_ICMP_ECHOREQ (8) /* ////////////////////////////////////////////////////////////////////////////////////// * types */ #include "tbox/prefix/packed.h" // the ip header type - rfc791 typedef struct __tb_ip_header_t { // version and ihl tb_uint8_t vihl; // type of service tb_uint8_t tos; // total length of the packet tb_uint16_t total_len; // unique identifier tb_uint16_t id; // flags and fragment offset tb_uint16_t frag_and_flags; // time to live tb_uint8_t ttl; // the protocol, tcp, udp, .. tb_uint8_t proto; // the checksum tb_uint16_t checksum; // the source ipaddr tb_uint32_t source_ip; // the dest ipaddr tb_uint32_t dest_ip; } __tb_packed__ tb_ip_header_t; // the icmp header type - rfc792 typedef struct __tb_icmp_header_t { // icmp type tb_uint8_t type; // type sub code tb_uint8_t code; // checksum tb_uint16_t checksum; // identifier tb_uint16_t id; // sequence numner tb_uint16_t seq; // data tb_byte_t data[1]; } __tb_packed__ tb_icmp_header_t; // the icmp echo request type typedef struct __tb_icmp_echo_request_t { // the icmp header tb_icmp_header_t icmp; // the request time tb_hong_t time; } __tb_packed__ tb_icmp_echo_request_t; // the icmp echo reply type typedef struct __tb_icmp_echo_reply_t { // the ip header tb_ip_header_t ip; // the echo request tb_icmp_echo_request_t request; } __tb_packed__ tb_icmp_echo_reply_t; #include "tbox/prefix/packed.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_uint16_t tb_calculate_checksum(tb_byte_t const* data, tb_long_t size) { // calculate sum tb_uint32_t sum = 0; tb_long_t nleft = size; tb_byte_t const* p = data; while (nleft > 1) { sum += tb_bits_get_u16_le(p); nleft -= 2; p += 2; } // calculate answer tb_uint16_t answer = 0; if (nleft == 1) { *(tb_byte_t *)(&answer) = *p; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return answer; } static tb_bool_t tb_ping_send(tb_socket_ref_t sock, tb_ipaddr_ref_t addr, tb_uint16_t seq) { // init echo tb_icmp_echo_request_t echo; tb_uint64_t time = tb_mclock(); echo.icmp.type = TB_ICMP_ECHOREQ; echo.icmp.code = 0; tb_bits_set_u16_le((tb_byte_t*)&echo.icmp.checksum, 0); tb_bits_set_u16_le((tb_byte_t*)&echo.icmp.id, 0xbeaf); tb_bits_set_u16_le((tb_byte_t*)&echo.icmp.seq, seq); tb_bits_set_u64_le((tb_byte_t*)&echo.time, time); tb_uint16_t checksum = tb_calculate_checksum((tb_byte_t const*)&echo, sizeof(echo)); tb_bits_set_u16_le((tb_byte_t*)&echo.icmp.checksum, checksum); // send echo tb_long_t send = 0; tb_long_t size = sizeof(echo); tb_bool_t wait = tb_false; tb_byte_t const* data = (tb_byte_t const*)&echo; while (send < size) { tb_long_t real = tb_socket_usend(sock, addr, data + send, size - send); if (real > 0) { send += real; wait = tb_false; } else if (!real && !wait) { wait = tb_true; real = tb_socket_wait(sock, TB_SOCKET_EVENT_SEND, -1); tb_assert_and_check_break(real > 0); } else break; } // ok? return send == size; } static tb_bool_t tb_ping_recv(tb_socket_ref_t sock, tb_uint16_t seq) { // recv echo tb_icmp_echo_reply_t echo; tb_long_t recv = 0; tb_long_t size = sizeof(echo); tb_bool_t wait = tb_false; tb_byte_t* data = (tb_byte_t*)&echo; while (recv < size) { tb_long_t real = tb_socket_urecv(sock, tb_null, data + recv, size - recv); if (real > 0) { recv += real; wait = tb_false; } else if (!real && !wait) { wait = tb_true; real = tb_socket_wait(sock, TB_SOCKET_EVENT_RECV, -1); tb_assert_and_check_break(real > 0); } else break; } tb_assert_and_check_return_val(recv == size, tb_false); // check protocol (icmp) tb_assert_and_check_return_val(echo.ip.proto == 1, tb_false); // check icmp type tb_assert_and_check_return_val(echo.request.icmp.type == TB_ICMP_ECHOREPLY, tb_false); // check id tb_assert_and_check_return_val(tb_bits_get_u16_le((tb_byte_t const*)&echo.request.icmp.id) == 0xbeaf, tb_false); // get source ip address tb_ipv4_t source_ip; source_ip.u32 = tb_bits_get_u32_le((tb_byte_t const*)&echo.ip.source_ip); // trace tb_uint64_t time = tb_bits_get_u64_le((tb_byte_t const*)&echo.request.time); tb_trace_i("%ld bytes from %{ipv4}: icmp_seq=%d ttl=%d time=%ld ms", size, &source_ip, seq, echo.ip.ttl, tb_mclock() - (tb_hong_t)time); // ok return tb_true; } static tb_void_t tb_demo_coroutine_ping(tb_cpointer_t priv) { // get address tb_ipaddr_ref_t addr = (tb_ipaddr_ref_t)priv; tb_assert_and_check_return(addr); // init socket tb_socket_ref_t sock = tb_socket_init(TB_SOCKET_TYPE_ICMP, TB_IPADDR_FAMILY_IPV4); if (sock) { // send ping tb_uint16_t i = 0; tb_uint16_t n = 10; while (i < n && tb_ping_send(sock, addr, i)) { // recv ping if (!tb_ping_recv(sock, i)) break; i++; // wait some time tb_sleep(1); } // exit socket tb_socket_exit(sock); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_ping_main(tb_int_t argc, tb_char_t** argv) { // check tb_assert_and_check_return_val(argc == 2 && argv[1], -1); // init addr tb_ipaddr_t addr; if (!tb_dns_looker_done(argv[1], &addr)) return -1; // trace tb_trace_i("PING %s (%{ipv4}): %d data bytes", argv[1], tb_ipaddr_ipv4(&addr), sizeof(tb_icmp_echo_request_t)); // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start ping tb_size_t n = 10; while (n--) { // start it tb_coroutine_start(scheduler, tb_demo_coroutine_ping, &addr, 0); } // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit scheduler tb_co_scheduler_exit(scheduler); } // end return 0; } tbox-1.7.6/src/demo/coroutine/pipe.c000066400000000000000000000034041467117505400173370ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define BUFSIZE (32767) #define COUNT (100000) /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t tb_demo_coroutine_writ(tb_cpointer_t priv) { tb_byte_t data[BUFSIZE]; tb_pipe_file_ref_t pipe = (tb_pipe_file_ref_t) priv; for (tb_size_t i = 0; i < COUNT; i++) { if (!tb_pipe_file_bwrit(pipe, data, sizeof(data))) break; tb_trace_i("[-->] %.4llu", i); } tb_pipe_file_exit(pipe); } static tb_void_t tb_demo_coroutine_read(tb_cpointer_t priv) { tb_byte_t data[BUFSIZE]; tb_pipe_file_ref_t pipe = (tb_pipe_file_ref_t) priv; for (tb_size_t count = 0;; count++) { if (!tb_pipe_file_bread(pipe, data, sizeof(data))) break; tb_trace_i("[<--] %.4llu", count); } tb_pipe_file_exit(pipe); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_pipe_main(tb_int_t argc, tb_char_t** argv) { tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { tb_pipe_file_ref_t pair[2]; if (tb_pipe_file_init_pair(pair, tb_null, 4096)) { // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_writ, pair[1], 0); tb_coroutine_start(scheduler, tb_demo_coroutine_read, pair[0], 0); // do loop tb_co_scheduler_loop(scheduler, tb_true); } tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/process.c000066400000000000000000000027151467117505400200640ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define COUNT (50) /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t tb_demo_coroutine_proc(tb_cpointer_t priv) { // get arguments tb_char_t** argv = (tb_char_t**)priv; tb_assert_and_check_return(argv); // init process tb_process_ref_t process = tb_process_init(argv[1], (tb_char_t const**)(argv + 1), tb_null); if (process) { // wait process tb_long_t status = 0; tb_process_wait(process, &status, -1); // trace tb_trace_i("run: %s, status: %ld", argv[1], status); // exit process tb_process_exit(process); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_process_main(tb_int_t argc, tb_char_t** argv) { tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start coroutines tb_size_t count = COUNT; while (count--) tb_coroutine_start(scheduler, tb_demo_coroutine_proc, argv, 0); // do loop tb_co_scheduler_loop(scheduler, tb_true); tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/process_pipe.c000066400000000000000000000054701467117505400211020ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ #define COUNT (50) /* ////////////////////////////////////////////////////////////////////////////////////// * private implementation */ static tb_void_t tb_demo_coroutine_proc(tb_cpointer_t priv) { // get arguments tb_char_t** argv = (tb_char_t**)priv; tb_assert_and_check_return(argv); // init id static tb_size_t count = 0; tb_size_t id = count++; // init pipe files tb_pipe_file_ref_t file[2] = {0}; if (tb_pipe_file_init_pair(file, tb_null, 0)) { // init process tb_process_attr_t attr = {0}; attr.out.pipe = file[1]; attr.outtype = TB_PROCESS_REDIRECT_TYPE_PIPE; tb_process_ref_t process = tb_process_init(argv[1], (tb_char_t const**)(argv + 1), &attr); if (process) { // read pipe data tb_size_t read = 0; tb_byte_t data[8192]; tb_size_t size = sizeof(data); tb_bool_t wait = tb_false; while (read < size) { tb_long_t real = tb_pipe_file_read(file[0], data + read, size - read); if (real > 0) { read += real; wait = tb_false; } else if (!real && !wait) { // wait pipe tb_long_t ok = tb_pipe_file_wait(file[0], TB_PIPE_EVENT_READ, 1000); tb_check_break(ok > 0); wait = tb_true; } else break; } // dump data tb_trace_i("[%lu]: read pipe: %ld", id, read); // wait process tb_long_t status = 0; tb_process_wait(process, &status, -1); // trace tb_trace_i("[%lu]: run: %s, status: %ld", id, argv[1], status); // exit process tb_process_exit(process); } // exit pipe files tb_pipe_file_exit(file[0]); tb_pipe_file_exit(file[1]); } // end tb_trace_i("[%lu]: end", id); } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_process_pipe_main(tb_int_t argc, tb_char_t** argv) { tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start coroutines tb_size_t count = COUNT; while (count--) tb_coroutine_start(scheduler, tb_demo_coroutine_proc, argv, 0); // do loop tb_co_scheduler_loop(scheduler, tb_true); tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/semaphore.c000066400000000000000000000042671467117505400203750ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_semaphore_wait_func(tb_cpointer_t priv) { // check tb_co_semaphore_ref_t semaphore = (tb_co_semaphore_ref_t)priv; tb_assert(semaphore); // loop while (1) { // wait it tb_long_t ok = tb_co_semaphore_wait(semaphore, -1); tb_assert_and_check_break(ok > 0); // trace tb_trace_i("[coroutine: %p]: wait ok", tb_coroutine_self()); } } static tb_void_t tb_demo_coroutine_semaphore_post_func(tb_cpointer_t priv) { // check tb_co_semaphore_ref_t semaphore = (tb_co_semaphore_ref_t)priv; tb_assert(semaphore); // loop while (1) { // trace tb_trace_i("[coroutine: %p]: post", tb_coroutine_self()); // post it tb_co_semaphore_post(semaphore, 2); // wait some time tb_msleep(1000); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_semaphore_main(tb_int_t argc, tb_char_t** argv) { // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // init semaphore tb_co_semaphore_ref_t semaphore = tb_co_semaphore_init(0); tb_assert(semaphore); // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_semaphore_wait_func, semaphore, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_semaphore_wait_func, semaphore, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_semaphore_wait_func, semaphore, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_semaphore_wait_func, semaphore, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_semaphore_post_func, semaphore, 0); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit semaphore tb_co_semaphore_exit(semaphore); // exit scheduler tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/sleep.c000066400000000000000000000030711467117505400175120ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_coroutine_sleep_func(tb_cpointer_t priv) { // the interval tb_size_t interval = (tb_size_t)priv; // loop tb_size_t count = 10; while (count--) { // get the start time tb_hong_t time = tb_mclock(); // sleep it tb_msleep(interval); // update the interval time time = tb_mclock() - time; // trace tb_trace_i("[coroutine: %lu]: count: %lu, interval: %lld ms", interval, count, time); } } /* ////////////////////////////////////////////////////////////////////////////////////// * main */ tb_int_t tb_demo_coroutine_sleep_main(tb_int_t argc, tb_char_t** argv) { // init scheduler tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init(); if (scheduler) { // start coroutines tb_coroutine_start(scheduler, tb_demo_coroutine_sleep_func, (tb_cpointer_t)1000, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_sleep_func, (tb_cpointer_t)2000, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_sleep_func, (tb_cpointer_t)10, 0); tb_coroutine_start(scheduler, tb_demo_coroutine_sleep_func, (tb_cpointer_t)100, 0); // run scheduler tb_co_scheduler_loop(scheduler, tb_true); // exit scheduler tb_co_scheduler_exit(scheduler); } return 0; } tbox-1.7.6/src/demo/coroutine/spider.c000066400000000000000000000420501467117505400176700ustar00rootroot00000000000000/* ////////////////////////////////////////////////////////////////////////////////////// * trace */ #define TB_TRACE_MODULE_NAME "spider" #define TB_TRACE_MODULE_DEBUG (1) /* ////////////////////////////////////////////////////////////////////////////////////// * includes */ #include "../demo.h" /* ////////////////////////////////////////////////////////////////////////////////////// * macros */ // the timeout //#define TB_DEMO_TIMEOUT (-1) #define TB_DEMO_TIMEOUT (15000) // the limit rate, 256KB/s #define TB_DEMO_LIMITRATE (0) //#define TB_DEMO_LIMITRATE (256000) // the filter maxn #define TB_DEMO_FILTER_MAXN (100000) // the task maxn #define TB_DEMO_TASK_MAXN (50) // the stack size #define TB_DEMO_STACKSIZE (8192 << 4) // the user agent #define TB_DEMO_USER_AGENT "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36" /* ////////////////////////////////////////////////////////////////////////////////////// * types */ // the spider type typedef struct __tb_demo_spider_t { // the homepage tb_char_t const* homepage; // the root directory tb_char_t rootdir[TB_PATH_MAXN]; // the bloom filter tb_bloom_filter_ref_t filter; // the urls tb_co_channel_ref_t urls; // the scheduler tb_co_scheduler_ref_t scheduler; }tb_demo_spider_t, *tb_demo_spider_ref_t; // the spider parser type typedef struct __tb_demo_spider_parser_t { // the stream tb_stream_ref_t stream; // the data tb_byte_t* data; // the data size tb_size_t size; // the data maxn tb_size_t maxn; // the data offset tb_size_t offset; // the path buffer tb_char_t path[TB_PATH_MAXN]; // the url tb_url_t url; }tb_demo_spider_parser_t, *tb_demo_spider_parser_ref_t; /* ////////////////////////////////////////////////////////////////////////////////////// * declaration */ static tb_void_t tb_demo_spider_urls_free(tb_pointer_t data, tb_cpointer_t priv); /* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ static tb_void_t tb_demo_spider_exit(tb_demo_spider_ref_t spider) { // check tb_assert_and_check_return(spider); // exit homepage if (spider->homepage) tb_free(spider->homepage); spider->homepage = tb_null; // exit filter if (spider->filter) tb_bloom_filter_exit(spider->filter); spider->filter = tb_null; // exit scheduler if (spider->scheduler) tb_co_scheduler_exit(spider->scheduler); spider->scheduler = tb_null; // exit urls if (spider->urls) tb_co_channel_exit(spider->urls); spider->urls = tb_null; // exit spider tb_free(spider); } static tb_demo_spider_ref_t tb_demo_spider_init(tb_char_t const* homepage, tb_char_t const* rootdir) { // check tb_assert_and_check_return_val(homepage, tb_null); // done tb_bool_t ok = tb_false; tb_demo_spider_ref_t spider = tb_null; do { // make spider spider = tb_malloc0_type(tb_demo_spider_t); tb_assert_and_check_break(spider); // init homepage spider->homepage = tb_strdup(homepage); tb_assert_and_check_break(spider->homepage); // init the root directory if (rootdir) tb_strlcpy(spider->rootdir, rootdir, sizeof(spider->rootdir)); else tb_directory_current(spider->rootdir, sizeof(spider->rootdir)); // init filter spider->filter = tb_bloom_filter_init(TB_BLOOM_FILTER_PROBABILITY_0_001, 3, TB_DEMO_FILTER_MAXN, tb_element_str(tb_true)); tb_assert_and_check_break(spider->filter); // init scheduler spider->scheduler = tb_co_scheduler_init(); tb_assert_and_check_break(spider->scheduler); // init urls spider->urls = tb_co_channel_init(TB_DEMO_TASK_MAXN, tb_demo_spider_urls_free, tb_null); tb_assert_and_check_break(spider->urls); // trace tb_trace_i("rootdir: %s, homepage: %s", spider->rootdir, spider->homepage); // ok ok = tb_true; } while (0); // failed if (!ok) { // exit it if (spider) tb_demo_spider_exit(spider); spider = tb_null; } // ok? return spider; } static tb_void_t tb_demo_spider_urls_free(tb_pointer_t data, tb_cpointer_t priv) { if (data) tb_free(data); } static tb_bool_t tb_demo_spider_make_ourl(tb_demo_spider_ref_t spider, tb_char_t const* url, tb_char_t* data, tb_size_t maxn) { // check tb_assert_and_check_return_val(spider && url && data && maxn, tb_false); // skip protocol tb_char_t* p = (tb_char_t*)url; if (!tb_strnicmp(p, "http://", 7)) p += 7; else if (!tb_strnicmp(p, "https://", 8)) p += 8; // skip space while (*p && tb_isspace(*p)) p++; // format ourl tb_long_t n = tb_snprintf(data, maxn, "%s/%s", spider->rootdir, p); tb_check_return_val(n > 0 && n < maxn, tb_false); // no root? append '/' if (!tb_strchr(p, '/') && !tb_strchr(p, '\\')) data[n++] = '/'; tb_assert_and_check_return_val(n < maxn, tb_false); // '\\' => '/' if (data[n - 1] == '/') data[n - 1] = '/'; // directory? append index.html if (data[n - 1] == '/') n += tb_snprintf(data + n, maxn - n, "%s", "index.html"); tb_assert_and_check_return_val(n > 0 && n < maxn, tb_false); // end data[n] = '\0'; // replace '?' => '_' p = data; while (*p) { // replace if (*p == '?') *p = '_'; // next p++; } // trace tb_trace_d("make: %s => %s", url, data); // ok? return n > 0? tb_true : tb_false; } static tb_bool_t tb_demo_spider_parser_open(tb_demo_spider_parser_ref_t parser, tb_char_t const* iurl, tb_char_t const* ourl) { // check tb_assert_and_check_return_val(parser && parser->stream && iurl && ourl, tb_false); // done tb_bool_t ok = tb_false; do { // find the .suffix tb_char_t const* p = tb_strrchr(ourl, '.'); if (p) { // not html? tb_check_break ( tb_stricmp(p, ".css") && tb_stricmp(p, ".js") && tb_stricmp(p, ".png") && tb_stricmp(p, ".jpg") && tb_stricmp(p, ".gif") && tb_stricmp(p, ".ico") && tb_stricmp(p, ".bmp") && tb_stricmp(p, ".mp4") && tb_stricmp(p, ".mp3") && tb_stricmp(p, ".flv") && tb_stricmp(p, ".avi") && tb_stricmp(p, ".exe") && tb_stricmp(p, ".msi") && tb_stricmp(p, ".zip") && tb_stricmp(p, ".rar") && tb_stricmp(p, ".7z")); } // ctrl stream if (!tb_stream_ctrl(parser->stream, TB_STREAM_CTRL_SET_URL, ourl)) break; // open stream if (!tb_stream_open(parser->stream)) break; // the stream size tb_hong_t size = tb_stream_size(parser->stream); tb_check_break(size && size < 1024 * 1024); // prefetch some data tb_byte_t* data = tb_null; tb_size_t need = tb_min((tb_size_t)size, 256); if (!tb_stream_need(parser->stream, &data, need)) break; // is html? if ( tb_strnistr((tb_char_t const*)data, need, "") || tb_strnistr((tb_char_t const*)data, need, "url, iurl)) break; // init data if (!parser->data) { parser->maxn = (tb_size_t)size + 1; parser->data = tb_malloc_bytes(parser->maxn); } else if (size + 1 > parser->maxn) { parser->maxn = (tb_size_t)size + 1; parser->data = tb_ralloc_bytes(parser->data, parser->maxn); } // read data if (parser->data && tb_stream_bread(parser->stream, parser->data, (tb_size_t)size)) { // save data parser->size = (tb_size_t)size; parser->offset = 0; parser->data[size] = '\0'; ok = tb_true; } } } while (0); // failed? if (!ok) tb_stream_clos(parser->stream); // ok? return ok; } static tb_void_t tb_demo_spider_parser_clos(tb_demo_spider_parser_ref_t parser) { // check tb_assert_and_check_return(parser); // reset data parser->size = 0; parser->offset = 0; // close stream if (parser->stream) tb_stream_clos(parser->stream); } static tb_char_t const* tb_demo_spider_parser_read(tb_demo_spider_parser_ref_t parser) { // check tb_assert_and_check_return_val(parser && parser->data && parser->size, tb_null); // end? tb_check_return_val(parser->offset + 16 < parser->size, tb_null); /* read the next url * * ? * * ? *