commit c8c1749347ba9e953ba9b7e098157042ee9dbe62 Author: Rongsong Shen Date: Thu Jan 29 17:22:53 2026 +0800 Import source to librtti Summary: - Import initial source Test Plan: NA diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..864a38d --- /dev/null +++ b/.clang-format @@ -0,0 +1,36 @@ +--- +BasedOnStyle: webkit +ColumnLimit: 80 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Left +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseColons: true +AlignEscapedNewlines: Right +AlignOperands: AlignAfterOperator +AlignTrailingComments: + Kind: Always + OverEmptyLines: 2 +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortEnumsOnASingleLine: false + +--- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d11506 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*~ +result diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a8a13d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2025 rshen + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +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 AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..14ce52d --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# rtti + +runtime type information library for c \ No newline at end of file diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..87b466d --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,18 @@ +# +#app_c_srcs=[ +# 'app.c', +#] +# +#app_srcs= app_c_srcs +# +#incdir = include_directories('../include', '.') +# +#app_deps = [ +# dep_librtti, +#] +# +#app = executable('app', +# app_srcs, +# include_directories: incdir, +# dependencies: app_deps, +# install: true) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..b73ec8f --- /dev/null +++ b/flake.lock @@ -0,0 +1,131 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1764950072, + "narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "f61125a668a320878494449750330ca58b78c557", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1764667669, + "narHash": "sha256-7WUCZfmqLAssbDqwg9cUDAXrSoXN79eEEq17qhTNM/Y=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "418468ac9527e799809c900eda37cbff999199b6", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "xbuild": "xbuild" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "xbuild": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1769064169, + "narHash": "sha256-Tqb8E8vw6WtP5KPCzwWAVBzMwv+UH0gduR2ZWkkYM9g=", + "owner": "shen390s", + "repo": "my-nix-channel", + "rev": "d6e6711f401446ebfec291ad1a3fbb58fd33720d", + "type": "github" + }, + "original": { + "owner": "shen390s", + "ref": "master", + "repo": "my-nix-channel", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..839a2ab --- /dev/null +++ b/flake.nix @@ -0,0 +1,42 @@ +{ + description = "Flake for librtti"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + xbuild.url = "github:shen390s/my-nix-channel?ref=master"; + }; + + outputs = + { + self, + nixpkgs, + flake-utils, + xbuild, + }: + let + supportedSystems = [ "x86_64-linux" ]; + in + flake-utils.lib.eachSystem supportedSystems ( + system: + let + mypkgs = xbuild.packages.${system}; + overlays = [ + (final: prev: mypkgs // prev) + ]; + pkgs = import nixpkgs { inherit overlays system; }; + xpkgs = import ./nixSupport/default.nix { + inherit pkgs; + }; + in + rec { + packages = pkgs // xpkgs; + defaultPackage = xpkgs.librtti_debug; + devShells.default = pkgs.mkShell { + nativeBuildInputs = xpkgs.librtti.nativeBuildInputs; + }; + + devShell = self.devShells.${system}.default; + } + ); +} diff --git a/include/rtti.h b/include/rtti.h new file mode 100644 index 0000000..cbf678f --- /dev/null +++ b/include/rtti.h @@ -0,0 +1,8 @@ +#if !defined(_LIBRTTI_RTTI_H_) + +#define _LIBRTTI_RTTI_H_ 1 + +#include "rtti/typeinfo.h" +#include "rtti/utils.h" + +#endif diff --git a/include/rtti/typeinfo.h b/include/rtti/typeinfo.h new file mode 100644 index 0000000..acaf015 --- /dev/null +++ b/include/rtti/typeinfo.h @@ -0,0 +1,142 @@ +#if !defined(_RTTI_TYPEINFO_H_) + +#define _RTTI_TYPEINFO_H_ 1 + +#include +#include +#include +#include +#include +#include + +#define var void* + +#define SIZE_ROUNDUP(sz) \ + ((((sz + sizeof(void*) - 1)) / (sizeof(void*))) * sizeof(void*)) + +#define OBJ_HEADER_SIZE SIZE_ROUNDUP(sizeof(meta_obj_t)) + +/** Object format + ** + ** +=====================+===================+===================+ + ** | | | <- public data > | + ** +=====================+===================+===================+ + ** + **/ +#define OBJ_TO_DATA(T, obj) ((T*)(((char*)obj) + OBJ_HEADER_SIZE)) +#define DATA_TO_OBJ(v) ((meta_obj_t*)(((char*)v) - OBJ_HEADER_SIZE)) +#define OBJ_TO_PRIV(obj) \ + ((void*)(((char*)obj) - SIZE_ROUNDUP((obj)->type->privateSize))) + +struct meta_obj_; +struct typeinfo_; + +typedef struct meta_obj_ meta_obj_t; +typedef struct typeinfo_ typeinfo_t; + +/* calculate the size of data */ +typedef size_t (*datasize_fn_t)(va_list); + +/* object life cycle */ +typedef int (*obj_init_fn_t)(typeinfo_t*, va_list); +typedef void (*obj_destroy_fn_t)(var); + +/* lock/unlock */ +typedef int (*lock_fn_t)(var, uint64_t); +typedef void (*unlock_fn_t)(var); + +typedef struct { + lock_fn_t lock; + unlock_fn_t unlock; +} intf_lock_t; + +/* convert to string */ +typedef char* (*to_string_fn_t)(var, va_list); + +typedef struct { + to_string_fn_t toString; +} intf_tostring_t; + +/* iterator function */ + +#define ITER_NO_DATA (0) +#define ITER_OK (1) + +typedef struct { + var v; + var data; +} iterator_t; + +typedef int (*iter_make_fn_t)(iterator_t*, var); +typedef int (*iter_next_fn_t)(iterator_t*, void**); +typedef int (*iter_reset_fn_t)(iterator_t*); +typedef void (*iter_destroy_fn_t)(iterator_t*); + +typedef struct { + iter_make_fn_t make; + iter_next_fn_t next; + iter_reset_fn_t reset; + iter_destroy_fn_t destroy; +} intf_iterator_t; + +/* reference and deref */ +typedef int32_t (*reference_fn_t)(var); +typedef void (*dereference_fn_t)(var); + +typedef struct { + reference_fn_t reference; + dereference_fn_t dereference; +} intf_reference_t; + +/* hash */ + +typedef int32_t (*hash_fn_t)(var); + +typedef struct { + hash_fn_t hash; +} intf_hash_t; + +/* length */ +typedef int64_t (*length_fn_t)(var); + +typedef struct { + length_fn_t length; +} intf_length_t; + +typedef struct { + intf_lock_t* lock; + intf_tostring_t* toString; + intf_iterator_t* iter; + intf_reference_t* reference; + intf_hash_t* hash; + intf_length_t* length; +} interface_table_t; + +struct typeinfo_ { + char* name; + size_t privateSize; + datasize_fn_t dataSize; + obj_init_fn_t init; + obj_destroy_fn_t destroy; + interface_table_t interfaces; +}; + +struct meta_obj_ { + typeinfo_t* type; +}; + +extern var makeInstance(typeinfo_t*, ...); +extern void destroy(var); +extern int lock(var, uint64_t); +extern void unlock(var); +extern char* toString(var, ...); +extern int iter_make(iterator_t*, var); +extern int iter_next(iterator_t*, void**); +extern int iter_reset(iterator_t*); +extern void iter_destroy(iterator_t*); +extern int32_t hash(var); +extern int64_t length(var); +extern int32_t reference(var); +extern void dereference(var); + +#endif diff --git a/include/rtti/utils.h b/include/rtti/utils.h new file mode 100644 index 0000000..7511262 --- /dev/null +++ b/include/rtti/utils.h @@ -0,0 +1,30 @@ +#if !defined(_RTTI_UTILS_H_) + +#define _RTTI_UTILS_H_ 1 + +#define RTTI_GET_METHOD(result, obj, intf, method) \ + do { \ + typeinfo_t* type_ = NULL; \ + meta_obj_t* obj_ = NULL; \ + \ + (result) = NULL; \ + \ + if ((obj) == NULL) { \ + break; \ + } \ + \ + obj_ = DATA_TO_OBJ(obj); \ + \ + type_ = obj_->type; \ + if (type_ == NULL) { \ + break; \ + } \ + \ + if (type_->interfaces.intf == NULL) { \ + break; \ + } \ + \ + (result) = type_->interfaces.intf->method; \ + } while (0) + +#endif diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..9717b72 --- /dev/null +++ b/meson.build @@ -0,0 +1,18 @@ +project('librtti', + ['c'], + version: '0.0.1', + meson_version: '>=1.5', + default_options: [ + 'c_std=gnu17']) + +add_project_arguments(['-ggdb', + '-g3', + '-Wno-cpp'], + language: ['c']) + +subdir('src') +if get_option('with_debug') == true + subdir('testsuite') +endif +# subdir('examples') + diff --git a/meson.options b/meson.options new file mode 100644 index 0000000..b4ff5dd --- /dev/null +++ b/meson.options @@ -0,0 +1 @@ +option('with_debug', type: 'boolean', value: false, yield: true) diff --git a/nixSupport/default.nix b/nixSupport/default.nix new file mode 100644 index 0000000..8e8d136 --- /dev/null +++ b/nixSupport/default.nix @@ -0,0 +1,20 @@ +{ + pkgs, + ... +}: +let + librtti = pkgs.callPackage ./librtti.nix { + inherit pkgs; + withDebug = false; + withAsan = false; + }; + librtti_debug = pkgs.callPackage ./librtti.nix { + inherit pkgs; + withDebug = true; + withAsan = true; + }; +in +{ + librtti = librtti; + librtti_debug = librtti_debug; +} diff --git a/nixSupport/librtti.nix b/nixSupport/librtti.nix new file mode 100644 index 0000000..b992879 --- /dev/null +++ b/nixSupport/librtti.nix @@ -0,0 +1,35 @@ +{ + lib, + stdenv, + pkgs, + withDebug ? false, + ... +}: + +stdenv.mkDerivation { + + pname = "rtti"; + version = "0.0.1"; + + src = ./..; + + nativeBuildInputs = with pkgs; [ + meson + ninja + pkg-config + which + unity_test_with_color + ]; + + build-system = [ pkgs.meson ]; + + dontStrip = withDebug; + separateDebugInfo = withDebug; + + impureEnvVars = [ "HOME" ]; + + mesonFlags = [ + (lib.optional withDebug "--buildtype=debug -Db_sanitize=address -Dwith_debug=true ") + # (lib.optional (!with_debug) "-Dbuildtype=release") + ]; +} diff --git a/src/create.c b/src/create.c new file mode 100644 index 0000000..2ae896e --- /dev/null +++ b/src/create.c @@ -0,0 +1,81 @@ +#include +#include + +#include "rtti.h" + +static void* objAlloc(typeinfo_t* type, size_t sz) +{ + size_t privateSize = SIZE_ROUNDUP(type->privateSize); + size_t headerSize = OBJ_HEADER_SIZE; + char* p = NULL; + meta_obj_t* obj = NULL; + size_t total = privateSize + headerSize + sz; + + p = (char*)calloc(1, total); + if (p == NULL) { + return NULL; + } + + obj = (meta_obj_t*)(p + privateSize); + obj->type = type; + + return (void*)(p + privateSize + headerSize); +} + +var makeInstance(typeinfo_t* type, ...) +{ + va_list ap; + va_list ap1; + var v = NULL; + int rc = 0; + + if ((type == NULL) || (type->init == NULL) || (type->dataSize == NULL)) { + errno = EINVAL; + return NULL; + } + + va_start(ap, type); + va_copy(ap1, ap); + v = objAlloc(type, type->dataSize(ap1)); + va_end(ap1); + + if (v != NULL) { + rc = type->init(v, ap); + } + + va_end(ap); + + if (rc < 0) { + destroy(v); + v = NULL; + } + + return v; +} + +void destroy(var v) +{ + typeinfo_t* type = NULL; + meta_obj_t* obj = NULL; + void* p = NULL; + + if (v == NULL) { + return; + } + + obj = DATA_TO_OBJ(v); + + type = obj->type; + if (type == NULL) { + return; + } + + if (type->destroy != NULL) { + type->destroy(v); + } + + p = OBJ_TO_PRIV(obj); + free(p); + + return; +} diff --git a/src/iter.c b/src/iter.c new file mode 100644 index 0000000..37fa4f4 --- /dev/null +++ b/src/iter.c @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "rtti.h" + +int iter_make(iterator_t* it, var v) +{ + iter_make_fn_t method = NULL; + + if (it == NULL) { + return -EINVAL; + } + + RTTI_GET_METHOD(method, v, iter, make); + if (method == NULL) { + return -EINVAL; + } + + memset(it, 0x0, sizeof(*it)); + it->v = v; + + return method(it, v); +} + +int iter_next(iterator_t* it, void** data) +{ + iter_next_fn_t method = NULL; + + if ((it == NULL) || (data == NULL) || (it->v == NULL)) { + return -EINVAL; + } + + RTTI_GET_METHOD(method, it->v, iter, next); + if (method == NULL) { + return -EINVAL; + } + + return method(it, data); +} + +int iter_reset(iterator_t* it) +{ + iter_reset_fn_t method = NULL; + + if ((it == NULL) || (it->v == NULL)) { + return -EINVAL; + } + + RTTI_GET_METHOD(method, it->v, iter, reset); + if (method == NULL) { + return -EINVAL; + } + + return method(it); +} + +void iter_destroy(iterator_t* it) +{ + iter_destroy_fn_t method = NULL; + + if ((it == NULL) || (it->v == NULL)) { + return; + } + + RTTI_GET_METHOD(method, it->v, iter, destroy); + if (method == NULL) { + return; + } + + method(it); + + return; +} diff --git a/src/lock.c b/src/lock.c new file mode 100644 index 0000000..6b31408 --- /dev/null +++ b/src/lock.c @@ -0,0 +1,30 @@ +#include +#include + +#include "rtti.h" + +int lock(var v, uint64_t option) +{ + lock_fn_t method = NULL; + + RTTI_GET_METHOD(method, v, lock, lock); + if (method == NULL) { + return -EINVAL; + } + + return method(v, option); +} + +void unlock(var v) +{ + unlock_fn_t method = NULL; + + RTTI_GET_METHOD(method, v, lock, unlock); + if (method == NULL) { + return; + } + + method(v); + + return; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..db6278b --- /dev/null +++ b/src/meson.build @@ -0,0 +1,42 @@ +pkg = import('pkgconfig') + +librtti_c_srcs=[ + 'create.c', + 'lock.c', + 'iter.c', + 'ref.c', + 'str.c', +] + + +librtti_srcs= librtti_c_srcs + +incdir = include_directories('../include', '.') + +rtti_top_headers = [ + '../include/rtti.h', +] + +rtti_headers = [ + '../include/rtti/typeinfo.h', + '../include/rtti/utils.h', +] + +librtti_deps = [ +] + +librtti = static_library('librtti', + librtti_srcs, + include_directories: incdir, + dependencies: librtti_deps, + install: true) + +install_headers(rtti_top_headers, install_dir: 'include') +install_headers(rtti_headers, install_dir: 'include/rtti') + +dep_librtti = declare_dependency(link_with: librtti) + +pkg.generate(librtti, + name: 'librtti', + description: 'runtime type information library for c', + version: '0.0.1') diff --git a/src/ref.c b/src/ref.c new file mode 100644 index 0000000..7535e60 --- /dev/null +++ b/src/ref.c @@ -0,0 +1,29 @@ +#include +#include +#include + +#include "rtti.h" + +int32_t reference(var v) +{ + reference_fn_t method = NULL; + + RTTI_GET_METHOD(method, v, reference, reference); + if (method == NULL) { + return -EINVAL; + } + + return method(v); +} + +void dereference(var v) +{ + dereference_fn_t method = NULL; + + RTTI_GET_METHOD(method,v, reference, dereference); + if (method != NULL) { + method(v); + } + + return; +} diff --git a/src/str.c b/src/str.c new file mode 100644 index 0000000..1d3f112 --- /dev/null +++ b/src/str.c @@ -0,0 +1,23 @@ +#include +#include + +#include "rtti.h" + +char* toString(var v, ...) +{ + to_string_fn_t method = NULL; + va_list ap; + char* s = NULL; + + RTTI_GET_METHOD(method, v, toString, toString); + if (method == NULL) { + errno = -EINVAL; + return NULL; + } + + va_start(ap, v); + s = method(v, ap); + va_end(ap); + + return s; +} diff --git a/testsuite/meson.build b/testsuite/meson.build new file mode 100644 index 0000000..ab6519d --- /dev/null +++ b/testsuite/meson.build @@ -0,0 +1,13 @@ +librtti_test_srcs = [ + 'test.c', + 'test_iter.c', +] + +unity_dep = dependency('unity') +librtti_test_deps = [dep_librtti, unity_dep] + +librtti_test = executable('rtti_test', + librtti_test_srcs, + include_directories: [incdir], + dependencies: librtti_test_deps, + install: true) diff --git a/testsuite/test.c b/testsuite/test.c new file mode 100644 index 0000000..b7465ed --- /dev/null +++ b/testsuite/test.c @@ -0,0 +1,29 @@ +#include +#include + +#include + +void setUp(void) +{ + printf("\n"); + return; +} + +void tearDown(void) +{ + printf("\n"); + return; +} + +extern void test_iter(void); + +#define TEST(x) x() + +int main(int argc, char* argv[]) +{ + UNITY_BEGIN(); + + TEST(test_iter); + + return UNITY_END(); +} diff --git a/testsuite/test_iter.c b/testsuite/test_iter.c new file mode 100644 index 0000000..f08a2f1 --- /dev/null +++ b/testsuite/test_iter.c @@ -0,0 +1,153 @@ +#include +#include +#include + +#include "rtti.h" + +typedef struct { + int count; + int* data; +} myArray_t; + +static size_t my_array_datasize(va_list ap) { return sizeof(myArray_t); } + +static int my_array_init(myArray_t* a, va_list ap) +{ + int count; + int i; + + count = va_arg(ap, int); + if (count <= 0) { + return -EINVAL; + } + + a->data = (int*)calloc(count, sizeof(int)); + if (a->data == NULL) { + return -ENOMEM; + } + + a->count = count; + for (i = 0; i < count; i++) { + a->data[i] = va_arg(ap, int); + } + + return 1; +} + +static void my_array_destroy(myArray_t* a) +{ + if (a->data != NULL) { + free(a->data); + a->data = NULL; + } +} + +static int my_array_make_iter(iterator_t* iter, var obj) +{ + iter->data = (void*)(long)0; + + return ITER_OK; +} + +static int my_array_iter_next(iterator_t* iter, void** data) +{ + myArray_t* a = iter->v; + int idx = (int)(long)iter->data; + + if (idx >= a->count) { + /* no data */ + return ITER_NO_DATA; + } + + *data = (void*)(long)a->data[idx]; + iter->data = (void*)(long)(idx + 1); + + return ITER_OK; +} + +static int my_array_iter_reset(iterator_t* iter) +{ + iter->data = (void*)(long)0; + + return ITER_OK; +} + +static void my_array_iter_destroy(iterator_t* iter) { return; } + +static typeinfo_t myintArray + = { .name = "myintArray", + .privateSize = 0, + .dataSize = (datasize_fn_t)my_array_datasize, + .init = (obj_init_fn_t)my_array_init, + .destroy = (obj_destroy_fn_t)my_array_destroy, + .interfaces + = { .iter = &(intf_iterator_t) { + .make = (iter_make_fn_t)my_array_make_iter, + .next = (iter_next_fn_t)my_array_iter_next, + .reset = (iter_reset_fn_t)my_array_iter_reset, + .destroy = (iter_destroy_fn_t)my_array_iter_destroy } } }; + +static void test_array_iter(void) +{ + var array = makeInstance(&myintArray, 5, 0, 1, 2, 3, 4); + iterator_t it; + int rc, sum; + void* data; + + TEST_ASSERT_TRUE(array != NULL); + + rc = iter_make(&it, array); + TEST_ASSERT_TRUE(rc == 1); + + rc = iter_next(&it, (void**)&data); + TEST_ASSERT_TRUE(rc >= 0); + TEST_ASSERT_TRUE((int)(long)data == 0); + + rc = iter_next(&it, (void**)&data); + TEST_ASSERT_TRUE(rc >= 0); + TEST_ASSERT_TRUE((int)(long)data == 1); + + rc = iter_next(&it, (void**)&data); + TEST_ASSERT_TRUE(rc >= 0); + TEST_ASSERT_TRUE((int)(long)data == 2); + + rc = iter_next(&it, (void**)&data); + TEST_ASSERT_TRUE(rc >= 0); + TEST_ASSERT_TRUE((int)(long)data == 3); + + rc = iter_next(&it, (void**)&data); + TEST_ASSERT_TRUE(rc >= 0); + TEST_ASSERT_TRUE((int)(long)data == 4); + + rc = iter_next(&it, (void**)&data); + TEST_ASSERT_TRUE(rc == ITER_NO_DATA); + + sum = 0; + rc = iter_reset(&it); + TEST_ASSERT_TRUE(rc >= 0); + + for (;;) { + rc = iter_next(&it, &data); + TEST_ASSERT_TRUE(rc >= 0); + if (rc == ITER_NO_DATA) { + break; + } + + sum += (int)(long)data; + } + + TEST_ASSERT_TRUE(sum == 10); + + iter_destroy(&it); + + destroy(array); + + return; +} + +void test_iter(void) +{ + printf("\n iterator test\n\n"); + + RUN_TEST(test_array_iter); +}