├── .codecov.yml ├── .codedocs ├── .github └── workflows │ └── build.yml ├── .gitignore ├── Doxyfile ├── LICENSE ├── Makefile ├── README.md ├── compile_headers.py ├── containers.h ├── documentation.md ├── src ├── array.c ├── deque.c ├── forward_list.c ├── include │ ├── VERSION │ ├── _bk_defines.h │ ├── array.h │ ├── deque.h │ ├── forward_list.h │ ├── list.h │ ├── map.h │ ├── multimap.h │ ├── multiset.h │ ├── priority_queue.h │ ├── queue.h │ ├── set.h │ ├── stack.h │ ├── unordered_map.h │ ├── unordered_multimap.h │ ├── unordered_multiset.h │ ├── unordered_set.h │ └── vector.h ├── list.c ├── map.c ├── multimap.c ├── multiset.c ├── priority_queue.c ├── queue.c ├── set.c ├── stack.c ├── unordered_map.c ├── unordered_multimap.c ├── unordered_multiset.c ├── unordered_set.c └── vector.c └── tst ├── test.c ├── test.h ├── test_array.c ├── test_deque.c ├── test_forward_list.c ├── test_list.c ├── test_map.c ├── test_multimap.c ├── test_multiset.c ├── test_priority_queue.c ├── test_queue.c ├── test_set.c ├── test_stack.c ├── test_unordered_map.c ├── test_unordered_multimap.c ├── test_unordered_multiset.c ├── test_unordered_set.c └── test_vector.c /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "tst" 3 | -------------------------------------------------------------------------------- /.codedocs: -------------------------------------------------------------------------------- 1 | DOXYFILE = Doxyfile 2 | 3 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push] 3 | jobs: 4 | debug: 5 | runs-on: ${{ matrix.os }} 6 | strategy: 7 | matrix: 8 | os: [ubuntu-latest, macos-latest] 9 | steps: 10 | - uses: actions/checkout@v3 11 | - run: make test_debug 12 | - run: ./ContainersTest 13 | debug_windows: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [windows-latest] 18 | steps: 19 | - uses: actions/checkout@v3 20 | - run: make test_debug_no_malloc_fail 21 | - run: ./ContainersTest 22 | optimized: 23 | runs-on: ${{ matrix.os }} 24 | strategy: 25 | matrix: 26 | os: [ubuntu-latest, macos-latest] 27 | steps: 28 | - uses: actions/checkout@v3 29 | - run: make test_optimized 30 | - run: ./ContainersTest 31 | optimized_windows: 32 | runs-on: ${{ matrix.os }} 33 | strategy: 34 | matrix: 35 | os: [windows-latest] 36 | steps: 37 | - uses: actions/checkout@v3 38 | - run: make test_optimized_no_malloc_fail 39 | - run: ./ContainersTest 40 | coverage: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - uses: actions/checkout@v3 44 | - run: make test_coverage 45 | - run: ./ContainersTest 46 | - run: bash <(curl -s https://codecov.io/bash) 47 | valgrind: 48 | runs-on: ubuntu-latest 49 | steps: 50 | - uses: actions/checkout@v3 51 | - run: sudo apt install -y valgrind 52 | - run: make test_debug_no_malloc_fail 53 | - run: valgrind --leak-check=full --error-exitcode=1 ./ContainersTest 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | cmake-build-debug/* 3 | venv/* 4 | docs/* 5 | containers.a 6 | containers.so 7 | CMakeCache.txt 8 | CMakeFiles/* 9 | Containers 10 | ContainersTest* 11 | Containers.cbp 12 | cmake_install.cmake 13 | CMakeLists.txt 14 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | DOXYFILE_ENCODING = UTF-8 2 | PROJECT_NAME = Containers 3 | PROJECT_NUMBER = 4 | PROJECT_BRIEF = "This library provides various containers. Each container has utility functions to manipulate the data it holds. This is an abstraction as to not have to manually manage and reallocate memory." 5 | PROJECT_LOGO = 6 | OUTPUT_DIRECTORY = docs 7 | CREATE_SUBDIRS = NO 8 | ALLOW_UNICODE_NAMES = NO 9 | OUTPUT_LANGUAGE = English 10 | OUTPUT_TEXT_DIRECTION = None 11 | BRIEF_MEMBER_DESC = YES 12 | REPEAT_BRIEF = YES 13 | ABBREVIATE_BRIEF = "The $name class" \ 14 | "The $name widget" \ 15 | "The $name file" \ 16 | is \ 17 | provides \ 18 | specifies \ 19 | contains \ 20 | represents \ 21 | a \ 22 | an \ 23 | the 24 | ALWAYS_DETAILED_SEC = NO 25 | INLINE_INHERITED_MEMB = NO 26 | FULL_PATH_NAMES = YES 27 | STRIP_FROM_PATH = 28 | STRIP_FROM_INC_PATH = 29 | SHORT_NAMES = NO 30 | JAVADOC_AUTOBRIEF = NO 31 | QT_AUTOBRIEF = NO 32 | MULTILINE_CPP_IS_BRIEF = NO 33 | INHERIT_DOCS = YES 34 | SEPARATE_MEMBER_PAGES = NO 35 | TAB_SIZE = 4 36 | ALIASES = 37 | TCL_SUBST = 38 | OPTIMIZE_OUTPUT_FOR_C = YES 39 | OPTIMIZE_OUTPUT_JAVA = NO 40 | OPTIMIZE_FOR_FORTRAN = NO 41 | OPTIMIZE_OUTPUT_VHDL = NO 42 | OPTIMIZE_OUTPUT_SLICE = NO 43 | EXTENSION_MAPPING = 44 | MARKDOWN_SUPPORT = YES 45 | TOC_INCLUDE_HEADINGS = 0 46 | AUTOLINK_SUPPORT = YES 47 | BUILTIN_STL_SUPPORT = NO 48 | CPP_CLI_SUPPORT = NO 49 | SIP_SUPPORT = NO 50 | IDL_PROPERTY_SUPPORT = YES 51 | DISTRIBUTE_GROUP_DOC = NO 52 | GROUP_NESTED_COMPOUNDS = NO 53 | SUBGROUPING = YES 54 | INLINE_GROUPED_CLASSES = NO 55 | INLINE_SIMPLE_STRUCTS = NO 56 | TYPEDEF_HIDES_STRUCT = NO 57 | LOOKUP_CACHE_SIZE = 0 58 | 59 | EXTRACT_ALL = YES 60 | EXTRACT_PRIVATE = NO 61 | EXTRACT_PACKAGE = NO 62 | EXTRACT_STATIC = NO 63 | EXTRACT_LOCAL_CLASSES = NO 64 | EXTRACT_LOCAL_METHODS = NO 65 | EXTRACT_ANON_NSPACES = NO 66 | HIDE_UNDOC_MEMBERS = NO 67 | HIDE_UNDOC_CLASSES = NO 68 | HIDE_FRIEND_COMPOUNDS = NO 69 | HIDE_IN_BODY_DOCS = NO 70 | INTERNAL_DOCS = NO 71 | CASE_SENSE_NAMES = NO 72 | HIDE_SCOPE_NAMES = NO 73 | HIDE_COMPOUND_REFERENCE= NO 74 | SHOW_INCLUDE_FILES = YES 75 | SHOW_GROUPED_MEMB_INC = NO 76 | FORCE_LOCAL_INCLUDES = NO 77 | INLINE_INFO = YES 78 | SORT_MEMBER_DOCS = YES 79 | SORT_BRIEF_DOCS = NO 80 | SORT_MEMBERS_CTORS_1ST = NO 81 | SORT_GROUP_NAMES = NO 82 | SORT_BY_SCOPE_NAME = NO 83 | STRICT_PROTO_MATCHING = NO 84 | GENERATE_TODOLIST = YES 85 | GENERATE_TESTLIST = YES 86 | GENERATE_BUGLIST = YES 87 | GENERATE_DEPRECATEDLIST= YES 88 | ENABLED_SECTIONS = 89 | MAX_INITIALIZER_LINES = 30 90 | SHOW_USED_FILES = YES 91 | SHOW_FILES = YES 92 | SHOW_NAMESPACES = YES 93 | FILE_VERSION_FILTER = 94 | LAYOUT_FILE = 95 | CITE_BIB_FILES = 96 | 97 | QUIET = NO 98 | WARNINGS = YES 99 | WARN_IF_UNDOCUMENTED = YES 100 | WARN_IF_DOC_ERROR = YES 101 | WARN_NO_PARAMDOC = NO 102 | WARN_AS_ERROR = NO 103 | WARN_FORMAT = "$file:$line: $text" 104 | WARN_LOGFILE = 105 | 106 | INPUT = 107 | INPUT_ENCODING = UTF-8 108 | FILE_PATTERNS = *.h \ 109 | *.c \ 110 | *.md 111 | RECURSIVE = YES 112 | EXCLUDE = tst 113 | EXCLUDE_SYMLINKS = NO 114 | EXCLUDE_PATTERNS = 115 | EXCLUDE_SYMBOLS = 116 | EXAMPLE_PATH = 117 | EXAMPLE_PATTERNS = * 118 | EXAMPLE_RECURSIVE = NO 119 | IMAGE_PATH = 120 | INPUT_FILTER = 121 | FILTER_PATTERNS = 122 | FILTER_SOURCE_FILES = NO 123 | FILTER_SOURCE_PATTERNS = 124 | USE_MDFILE_AS_MAINPAGE = README.md 125 | 126 | SOURCE_BROWSER = NO 127 | INLINE_SOURCES = NO 128 | STRIP_CODE_COMMENTS = YES 129 | REFERENCED_BY_RELATION = NO 130 | REFERENCES_RELATION = NO 131 | REFERENCES_LINK_SOURCE = YES 132 | SOURCE_TOOLTIPS = YES 133 | USE_HTAGS = NO 134 | VERBATIM_HEADERS = YES 135 | CLANG_ASSISTED_PARSING = NO 136 | CLANG_OPTIONS = 137 | CLANG_DATABASE_PATH = 138 | 139 | ALPHABETICAL_INDEX = NO 140 | COLS_IN_ALPHA_INDEX = 5 141 | IGNORE_PREFIX = 142 | 143 | GENERATE_HTML = YES 144 | HTML_OUTPUT = html 145 | HTML_FILE_EXTENSION = .html 146 | HTML_HEADER = 147 | HTML_FOOTER = 148 | HTML_STYLESHEET = 149 | HTML_EXTRA_STYLESHEET = 150 | HTML_EXTRA_FILES = 151 | HTML_COLORSTYLE_HUE = 220 152 | HTML_COLORSTYLE_SAT = 100 153 | HTML_COLORSTYLE_GAMMA = 80 154 | HTML_TIMESTAMP = NO 155 | HTML_DYNAMIC_MENUS = YES 156 | HTML_DYNAMIC_SECTIONS = NO 157 | HTML_INDEX_NUM_ENTRIES = 100 158 | GENERATE_DOCSET = NO 159 | DOCSET_FEEDNAME = "Doxygen generated docs" 160 | DOCSET_BUNDLE_ID = org.doxygen.Project 161 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 162 | DOCSET_PUBLISHER_NAME = Publisher 163 | GENERATE_HTMLHELP = NO 164 | CHM_FILE = 165 | HHC_LOCATION = 166 | GENERATE_CHI = NO 167 | CHM_INDEX_ENCODING = 168 | BINARY_TOC = NO 169 | TOC_EXPAND = NO 170 | GENERATE_QHP = NO 171 | QCH_FILE = 172 | QHP_NAMESPACE = org.doxygen.Project 173 | QHP_VIRTUAL_FOLDER = doc 174 | QHP_CUST_FILTER_NAME = 175 | QHP_CUST_FILTER_ATTRS = 176 | QHP_SECT_FILTER_ATTRS = 177 | QHG_LOCATION = 178 | GENERATE_ECLIPSEHELP = NO 179 | ECLIPSE_DOC_ID = org.doxygen.Project 180 | DISABLE_INDEX = NO 181 | GENERATE_TREEVIEW = YES 182 | ENUM_VALUES_PER_LINE = 4 183 | TREEVIEW_WIDTH = 250 184 | EXT_LINKS_IN_WINDOW = NO 185 | FORMULA_FONTSIZE = 10 186 | FORMULA_TRANSPARENT = YES 187 | USE_MATHJAX = NO 188 | MATHJAX_FORMAT = HTML-CSS 189 | MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ 190 | MATHJAX_EXTENSIONS = 191 | MATHJAX_CODEFILE = 192 | SEARCHENGINE = YES 193 | SERVER_BASED_SEARCH = NO 194 | EXTERNAL_SEARCH = NO 195 | SEARCHENGINE_URL = 196 | SEARCHDATA_FILE = searchdata.xml 197 | EXTERNAL_SEARCH_ID = 198 | EXTRA_SEARCH_MAPPINGS = 199 | 200 | GENERATE_LATEX = NO 201 | LATEX_OUTPUT = latex 202 | LATEX_CMD_NAME = 203 | MAKEINDEX_CMD_NAME = makeindex 204 | LATEX_MAKEINDEX_CMD = \makeindex 205 | COMPACT_LATEX = NO 206 | PAPER_TYPE = a4 207 | EXTRA_PACKAGES = 208 | LATEX_HEADER = 209 | LATEX_FOOTER = 210 | LATEX_EXTRA_STYLESHEET = 211 | LATEX_EXTRA_FILES = 212 | PDF_HYPERLINKS = YES 213 | USE_PDFLATEX = YES 214 | LATEX_BATCHMODE = NO 215 | LATEX_HIDE_INDICES = NO 216 | LATEX_SOURCE_CODE = NO 217 | LATEX_BIB_STYLE = plain 218 | LATEX_TIMESTAMP = NO 219 | LATEX_EMOJI_DIRECTORY = 220 | 221 | GENERATE_RTF = NO 222 | RTF_OUTPUT = rtf 223 | COMPACT_RTF = NO 224 | RTF_HYPERLINKS = NO 225 | RTF_STYLESHEET_FILE = 226 | RTF_EXTENSIONS_FILE = 227 | RTF_SOURCE_CODE = NO 228 | 229 | GENERATE_MAN = NO 230 | MAN_OUTPUT = man 231 | MAN_EXTENSION = .3 232 | MAN_SUBDIR = 233 | MAN_LINKS = NO 234 | 235 | GENERATE_XML = NO 236 | XML_OUTPUT = xml 237 | XML_PROGRAMLISTING = YES 238 | XML_NS_MEMB_FILE_SCOPE = NO 239 | 240 | GENERATE_DOCBOOK = NO 241 | DOCBOOK_OUTPUT = docbook 242 | DOCBOOK_PROGRAMLISTING = NO 243 | 244 | GENERATE_AUTOGEN_DEF = NO 245 | 246 | GENERATE_PERLMOD = NO 247 | PERLMOD_LATEX = NO 248 | PERLMOD_PRETTY = YES 249 | PERLMOD_MAKEVAR_PREFIX = 250 | 251 | ENABLE_PREPROCESSING = YES 252 | MACRO_EXPANSION = NO 253 | EXPAND_ONLY_PREDEF = NO 254 | SEARCH_INCLUDES = YES 255 | INCLUDE_PATH = 256 | INCLUDE_FILE_PATTERNS = 257 | PREDEFINED = 258 | EXPAND_AS_DEFINED = 259 | SKIP_FUNCTION_MACROS = YES 260 | 261 | TAGFILES = 262 | GENERATE_TAGFILE = 263 | ALLEXTERNALS = NO 264 | EXTERNAL_GROUPS = YES 265 | EXTERNAL_PAGES = YES 266 | PERL_PATH = /usr/bin/perl 267 | 268 | CLASS_DIAGRAMS = NO 269 | MSCGEN_PATH = 270 | DIA_PATH = 271 | HIDE_UNDOC_RELATIONS = YES 272 | HAVE_DOT = NO 273 | DOT_NUM_THREADS = 0 274 | DOT_FONTNAME = Helvetica 275 | DOT_FONTSIZE = 10 276 | DOT_FONTPATH = 277 | CLASS_GRAPH = YES 278 | COLLABORATION_GRAPH = YES 279 | GROUP_GRAPHS = YES 280 | UML_LOOK = NO 281 | UML_LIMIT_NUM_FIELDS = 10 282 | TEMPLATE_RELATIONS = NO 283 | INCLUDE_GRAPH = YES 284 | INCLUDED_BY_GRAPH = YES 285 | CALL_GRAPH = NO 286 | CALLER_GRAPH = NO 287 | GRAPHICAL_HIERARCHY = YES 288 | DIRECTORY_GRAPH = YES 289 | DOT_IMAGE_FORMAT = png 290 | INTERACTIVE_SVG = NO 291 | DOT_PATH = 292 | DOTFILE_DIRS = 293 | MSCFILE_DIRS = 294 | DIAFILE_DIRS = 295 | PLANTUML_JAR_PATH = 296 | PLANTUML_CFG_FILE = 297 | PLANTUML_INCLUDE_PATH = 298 | DOT_GRAPH_MAX_NODES = 50 299 | MAX_DOT_GRAPH_DEPTH = 0 300 | DOT_TRANSPARENT = NO 301 | DOT_MULTI_TARGETS = NO 302 | GENERATE_LEGEND = YES 303 | DOT_CLEANUP = YES 304 | 305 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-2022 Bailey Thompson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := unspecified 2 | 3 | unspecified: 4 | @echo "Error: use 'make static_clang' or 'make dynamic_clang' or 'make static_gcc' or 'make dynamic_gcc'" 5 | 6 | static_clang: 7 | clang src/*.c -c -O3 -fpic 8 | ar rcs containers.a *.o 9 | rm *.o 10 | 11 | dynamic_clang: 12 | clang -shared -o containers.so -O3 -fPIC src/*.c 13 | 14 | static_gcc: 15 | gcc src/*.c -c -O3 -fpic 16 | ar rcs containers.a *.o 17 | rm *.o 18 | 19 | dynamic_gcc: 20 | gcc -shared -o containers.so -O3 -fPIC src/*.c 21 | 22 | header: 23 | python3 compile_headers.py $(version) 24 | 25 | test_debug: 26 | @gcc src/*.c tst/*.c -Wall -Wextra -Wpedantic -Werror -std=c89 -O0 -ldl -o ContainersTest 27 | 28 | test_optimized: 29 | @gcc src/*.c tst/*.c -Wall -Wextra -Wpedantic -Werror -std=c89 -O3 -ldl -o ContainersTest 30 | 31 | test_debug_no_malloc_fail: 32 | @sed -i 's/STUB_MALLOC 1/STUB_MALLOC 0/g' tst/test.h 33 | @gcc src/*.c tst/*.c -Wall -Wextra -Wpedantic -Werror -std=c89 -O0 -o ContainersTest 34 | @sed -i 's/STUB_MALLOC 0/STUB_MALLOC 1/g' tst/test.h 35 | 36 | test_optimized_no_malloc_fail: 37 | @sed -i 's/STUB_MALLOC 1/STUB_MALLOC 0/g' tst/test.h 38 | @gcc src/*.c tst/*.c -Wall -Wextra -Wpedantic -Werror -std=c89 -O3 -o ContainersTest 39 | @sed -i 's/STUB_MALLOC 0/STUB_MALLOC 1/g' tst/test.h 40 | 41 | test_coverage: 42 | @gcc src/*.c tst/*.c -Wall -Wextra -Wpedantic -Werror -std=c89 -O0 -ldl -g -coverage -o ContainersTest 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![GitHubBuild](https://github.com/bkthomps/Containers/workflows/build/badge.svg)](https://github.com/bkthomps/Containers) 2 | [![Documentation](https://codedocs.xyz/bkthomps/Containers.svg)](https://codedocs.xyz/bkthomps/Containers/) 3 | [![Codecov](https://codecov.io/gh/bkthomps/Containers/branch/master/graph/badge.svg)](https://codecov.io/gh/bkthomps/Containers) 4 | [![Language](https://img.shields.io/badge/language-C89+-orange.svg)](https://en.wikipedia.org/wiki/C_(programming_language)) 5 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/bkthomps/Containers/blob/master/LICENSE) 6 | 7 | # Containers 8 | This library provides various containers. Each container has utility functions 9 | to manipulate the data it holds. This is an abstraction as to not have to 10 | manually manage and reallocate memory. 11 | 12 | Inspired by the C++ standard library; however, implemented using C with 13 | different function interfaces as the C++ standard library but with the same 14 | container names. 15 | 16 | ## Setup 17 | It is possible to compile this library as either static `.a` or dynamic `.so`: 18 | 1. A static library is slightly faster than a dynamic one, however, if the 19 | library is modified, the entire project codebase which uses it will need to be 20 | relinked. 21 | 2. A dynamic library can be changed without relinking the codebase, assuming 22 | no function definitions have changed. 23 | 24 | The installation process is as follows: 25 | 1. Clone this repository and navigate to it. 26 | 2. Run `make static_clang`/`make static_gcc` or 27 | `make dynamic_clang`/`make dynamic_gcc` for either a static or dynamic library. 28 | 3. Then, you can copy-paste `containers.h` and `containers.a`/`containers.so` 29 | into your project to include the containers. 30 | 4. Finally, you remember to link the library by including 31 | `containers.a -ldl`/`containers.so -ldl` as an argument. 32 | 33 | ## Documentation 34 | For high-level documentation and usage, visit the 35 | [documentation](documentation.md) page. For in-depth documentation, visit the 36 | [code docs](https://codedocs.xyz/bkthomps/Containers/) page. 37 | 38 | ## Container Types 39 | The container types that this library contains are described below. 40 | 41 | ### Sequence containers 42 | Data structures which can be accessed sequentially. 43 | * array - static contiguous array 44 | * vector - dynamic contiguous array 45 | * deque - double-ended queue 46 | * forward_list - singly-linked list 47 | * list - doubly-linked list 48 | 49 | ### Associative containers 50 | Data structures that can be quickly searched which use comparators. 51 | * set - collection of unique keys, sorted by keys 52 | * map - collection of key-value pairs, sorted by keys, keys are unique 53 | * multiset - collection of keys, sorted by keys 54 | * multimap - collection of key-value pairs, sorted by keys 55 | 56 | ### Unordered associative containers 57 | Data structures that can be quickly searched which use hashing. 58 | * unordered_set - collection of unique keys, hashed by keys 59 | * unordered_map - collection of key-value pairs, hashed by keys, keys are unique 60 | * unordered_multiset - collection of keys, hashed by keys 61 | * unordered_multimap - collection of key-value pairs, hashed by keys 62 | 63 | ### Container adaptors 64 | Data structures which adapt other containers to enhance functionality. 65 | * stack - adapts a container to provide stack (last-in first-out) 66 | * queue - adapts a container to provide queue (first-in first-out) 67 | * priority_queue - adapts a container to provide priority queue 68 | -------------------------------------------------------------------------------- /compile_headers.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | import re 4 | import sys 5 | 6 | github_location = "github.com/bkthomps/Containers" 7 | 8 | if len(sys.argv) != 2: 9 | sys.exit("Format: python3 compile_headers.py ") 10 | version = str(sys.argv[1]) 11 | if not re.match(r"v[0-9]+\.[0-9]+\.[0-9]+", version): 12 | sys.exit("Error: version format must be: vi.j.k") 13 | 14 | license_list = [] 15 | license_file = open("LICENSE", "r") 16 | i = 0 17 | for line in license_file: 18 | if i >= 2: 19 | license_list.append(line) 20 | i += 1 21 | license_file.close() 22 | 23 | first_line = license_list[0].split(" ") 24 | name = "" 25 | i = 0 26 | for part in first_line: 27 | if i >= 3: 28 | name += part 29 | name += " " 30 | i += 1 31 | 32 | header = "/*\n" 33 | for line in license_list: 34 | if line == "\n": 35 | header += " *" + line 36 | else: 37 | header += " * " + line 38 | header += " */\n\n" 39 | header += "/*\n" 40 | header += " * The Containers library is hosted at: " + github_location + "\n" 41 | header += " * The author is: " + name 42 | header += "* This local version is: " + version + "\n" 43 | header += " */\n" 44 | 45 | version_file = open("src/include/VERSION", "w+") 46 | version_file.write(header) 47 | version_file.close() 48 | 49 | folder_path = 'src/include' 50 | for filename in sorted(glob.glob(os.path.join(folder_path, '*.h'))): 51 | with open(filename, 'r') as file: 52 | text = file.read() 53 | entire_file = text.split("*/", 1)[1] 54 | split_around_text = '#include "_bk_defines.h"\n\n' 55 | split_around_include = entire_file.split(split_around_text, 1) 56 | header += split_around_include[0] 57 | if len(split_around_include) == 2: 58 | header += split_around_include[1] 59 | 60 | containers_header_file = open("containers.h", "w+") 61 | containers_header_file.write(header) 62 | containers_header_file.close() 63 | -------------------------------------------------------------------------------- /documentation.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | For setup and compilation instructions visit the [readme](README.md). For 3 | in-depth documentation, visit the 4 | [code docs](https://codedocs.xyz/bkthomps/Containers/) page. 5 | 6 | ## General Overview 7 | Each container has an initialization function which returns a container object. 8 | For a deque, this would be `deque_init()` which returns a `deque`. The returned 9 | object is a pointer to an internal struct which contains information, but this 10 | is abstracted away to reduce mistakes and make development easier. More 11 | information about the initialization functions is presented below in its own 12 | section. 13 | 14 | Once a container object is initialized, it is possible to manipulate it using 15 | the provided functions, which have in-depth documentation available. Each 16 | container has adding and retrieval type functions, and each type of container 17 | has its own specific set of function interfaces, which are explained in-depth at 18 | the function level in the code docs link above. More high-level information will 19 | be explained in its own section below. 20 | 21 | Finally, each container will have to be destroyed to free the memory associated 22 | with it. 23 | 24 | # Container Initialization 25 | When creating a container, first you must decide what type of data you wish to 26 | store in it (or types for the case of a map). Then, you must either decide if 27 | you wish to store a copy of the data in the container, or a pointer to it. The 28 | benefit of a copy is that you don't have to manage the memory, and it is easier 29 | to reason. However, it might only be reasonable to store copies if the data type 30 | is relatively cheap to copy. Using pointers, you can either store references to 31 | automatic variables (make sure the lifetime stays valid while the data is 32 | stored), or dynamically-allocated variables (make sure to free at some point). 33 | Either way, you must pass in a pointer of what you wish to store, be it a 34 | pointer to a value, or a pointer to a pointer. Keep in mind that for some 35 | containers, changing data which is stored will cause undefined behavior. Fret 36 | not, as all containers document their potential undefined behavior in the 37 | function documentation comments. 38 | 39 | Going back to the initialization function and ways we can initialize containers 40 | and and store data, we can use an example of a `deque`: 41 | ``` 42 | deque a = deque_init(sizeof(int)); /* OK: cheap to copy */ 43 | deque b = deque_init(sizeof(struct expensive_data)); /* Bad: valid, but expensive to copy */ 44 | deque c = deque_init(sizeof(struct expensive_data *)); /* OK: pointer to expensive data, but be careful about memory management */ 45 | ``` 46 | 47 | Also, if the arguments which you passed in to the initialization function are 48 | invalid, or the system is out of memory, the initialization function may return 49 | NULL. Therefore, it is good to check for a return of NULL from the 50 | initialization functions. 51 | 52 | # Container Operations 53 | Next, the two basic container manipulation functions of containers are to add 54 | and remove elements. To add elements, pass a pointer of the element you wish to 55 | copy to the add function. To remove an element, pass a pointer to a variable 56 | which can store the size of element that is stored in the container. 57 | 58 | Using the `deque` example, adding and removal can be done this way (if storing 59 | int): 60 | ``` 61 | deque d = deque_init(sizeof(int)); 62 | ... 63 | int add = 5; 64 | bk_err rc = deque_push_back(d, &add); /* 5 has been added to the back of the deque */ 65 | ... 66 | int retrieve; 67 | bk_err rc = deque_pop_back(&retrieve, d); /* retrieve now is equal to 5 */ 68 | ... 69 | ``` 70 | 71 | Functions can fail for various reasons, such as the provided index argument 72 | being out of bounds, or the system running out of memory. The in-depth 73 | documentation linked above provides the exhaustive list of return codes for each 74 | function, which are present in the header file. For example, an invalid argument 75 | would return `-BK_EINVAL`, and on success `BK_OK` would be returned. 76 | 77 | # Comparators and Hash Functions 78 | The associative containers and the priority queue require the user to initialize 79 | the container with a comparator, and the unordered associative containers also 80 | require a hash function to be passed in. State should not be modified in 81 | comparators or in hash functions, or else it would lead to undefined behavior. 82 | 83 | When a comparator function is called, two arguments are passed in, being two 84 | elements to compare. The comparator must return 0 if they are equal, a negative 85 | value if the first is less than the second, and a positive value is the first is 86 | greater than the second. To be valid, a comparator must obey the following 87 | rules: 88 | 1. Reflexive: `arg_1 == arg_1` and `arg_2 == arg_2` must always be true 89 | 2. Symmetric: if `arg_1 == arg_2` is true, then `arg_2 == arg_1` is true 90 | 3. Transitive: if the comparator is called twice with three distinct objects, 91 | the first time being `(arg_1, arg_2)` and the second `(arg_2, arg_3)`, then if 92 | `arg_1 == arg_2` and `arg_2 == arg_3` then `arg_1 == arg_3` must be true 93 | 4. Consistent: the truth of `arg_1 == arg_2` shall never change over time if 94 | both arguments do not change 95 | 96 | When a hash function is called, it is provided one argument, and must hash its 97 | attributes. A hash is a mapping from the object to a number. Two objects which 98 | are equal must always result in the same hash being produced. The inverse is not 99 | required, but should be sufficiently improbable (meaning, two distinct objects 100 | may produce the same hash, but it should be very rare). 101 | 102 | Using unordered set as an example (and storing int), the comparator and hash 103 | function can be passed in as follows when initializing: 104 | ``` 105 | unordered_set_init(sizeof(int), hash_int, compare_int) 106 | ``` 107 | 108 | A comparator can be as follows: 109 | ``` 110 | static int compare_int(const void *const one, const void *const two) 111 | { 112 | const int a = *(int *) one; 113 | const int b = *(int *) two; 114 | return a - b; 115 | } 116 | ``` 117 | 118 | And a hash function can be as follows: 119 | ``` 120 | static unsigned long hash_int(const void *const key) 121 | { 122 | unsigned long hash = 17; 123 | hash = 31 * hash + *(int *) key; 124 | return hash; 125 | } 126 | ``` 127 | -------------------------------------------------------------------------------- /src/array.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "include/array.h" 25 | 26 | static const size_t book_keeping_size = sizeof(size_t); 27 | static const size_t arr_size_offset = 0; 28 | static const size_t data_size_offset = sizeof(size_t); 29 | static const size_t data_ptr_offset = 2 * sizeof(size_t); 30 | 31 | /** 32 | * Initializes an array. 33 | * 34 | * @param element_count the number of elements in the array; must not be 35 | * negative 36 | * @param data_size the size of each element in the array; must be positive 37 | * 38 | * @return the newly-initialized array, or NULL if it was not successfully 39 | * initialized due to either invalid input arguments or memory 40 | * allocation error 41 | */ 42 | array array_init(const size_t element_count, const size_t data_size) 43 | { 44 | char *init; 45 | if (data_size == 0) { 46 | return NULL; 47 | } 48 | if (element_count * data_size / data_size != element_count) { 49 | return NULL; 50 | } 51 | if (data_ptr_offset + element_count * data_size < data_ptr_offset) { 52 | return NULL; 53 | } 54 | init = malloc(data_ptr_offset + element_count * data_size); 55 | if (!init) { 56 | return NULL; 57 | } 58 | memcpy(init + arr_size_offset, &element_count, book_keeping_size); 59 | memcpy(init + data_size_offset, &data_size, book_keeping_size); 60 | memset(init + data_ptr_offset, 0, element_count * data_size); 61 | return init; 62 | } 63 | 64 | /** 65 | * Gets the size of the array. 66 | * 67 | * @param me the array to check 68 | * 69 | * @return the size of the array 70 | */ 71 | size_t array_size(array me) 72 | { 73 | size_t size; 74 | memcpy(&size, me + arr_size_offset, book_keeping_size); 75 | return size; 76 | } 77 | 78 | /** 79 | * Copies the array to a raw array. Since it is a copy, the raw array may be 80 | * modified without causing side effects to the array data structure. Memory 81 | * is not allocated, thus the raw array being used for the copy must be 82 | * allocated before this function is called. The size of the array should be 83 | * queried prior to calling this function, which also serves as the size of the 84 | * newly-copied raw array. 85 | * 86 | * @param arr the initialized raw array to copy the array to 87 | * @param me the array to copy to the raw array 88 | */ 89 | void array_copy_to_array(void *const arr, array me) 90 | { 91 | size_t element_count; 92 | size_t data_size; 93 | memcpy(&element_count, me + arr_size_offset, book_keeping_size); 94 | memcpy(&data_size, me + data_size_offset, book_keeping_size); 95 | memcpy(arr, me + data_ptr_offset, element_count * data_size); 96 | } 97 | 98 | /** 99 | * Gets the storage element of the array structure. The storage element is 100 | * contiguous in memory. The data pointer should be assigned to the correct 101 | * array type. For example, if the array holds integers, the data pointer should 102 | * be assigned to a raw integer array. The size of the array should be obtained 103 | * prior to calling this function, which also serves as the size of the queried 104 | * raw array. This pointer is not a copy, thus any modification to the data will 105 | * cause the array structure data to be modified. Operations using the array 106 | * functions may invalidate this pointer. The array owns this memory, thus it 107 | * should not be freed. If the array size if 0, this should not be used. 108 | * 109 | * @param me the array to get the storage element from 110 | * 111 | * @return the storage element of the array 112 | */ 113 | void *array_get_data(array me) 114 | { 115 | size_t element_count; 116 | memcpy(&element_count, me + arr_size_offset, book_keeping_size); 117 | if (element_count == 0) { 118 | return NULL; 119 | } 120 | return me + data_ptr_offset; 121 | } 122 | 123 | /** 124 | * Copies elements from a raw array to the array. The size specifies the number 125 | * of elements to copy starting from the start of the raw array, which must be 126 | * less than or equal to the size of both the raw array and of the array. The 127 | * elements are copied to the array starting at the start of the array. 128 | * 129 | * @param me the array to add data to 130 | * @param arr the raw array to copy data from 131 | * @param size the number of elements to copy 132 | * 133 | * @return BK_OK if no error 134 | * @return -BK_EINVAL if invalid argument 135 | */ 136 | bk_err array_add_all(array me, void *const arr, const size_t size) 137 | { 138 | size_t element_count; 139 | size_t data_size; 140 | memcpy(&element_count, me + arr_size_offset, book_keeping_size); 141 | if (size > element_count) { 142 | return -BK_EINVAL; 143 | } 144 | memcpy(&data_size, me + data_size_offset, book_keeping_size); 145 | memcpy(me + data_ptr_offset, arr, size * data_size); 146 | return BK_OK; 147 | } 148 | 149 | /** 150 | * Sets the data for a specified element in the array. The pointer to the data 151 | * being passed in should point to the data type which this array holds. For 152 | * example, if this array holds integers, the data pointer should be a pointer 153 | * to an integer. Since the data is being copied, the pointer only has to be 154 | * valid when this function is called. 155 | * 156 | * @param me the array to set data for 157 | * @param index the location to set data at in the array 158 | * @param data the data to set at the location in the array 159 | * 160 | * @return BK_OK if no error 161 | * @return -BK_EINVAL if invalid argument 162 | */ 163 | bk_err array_set(array me, const size_t index, void *const data) 164 | { 165 | size_t element_count; 166 | size_t data_size; 167 | memcpy(&element_count, me + arr_size_offset, book_keeping_size); 168 | if (index >= element_count) { 169 | return -BK_EINVAL; 170 | } 171 | memcpy(&data_size, me + data_size_offset, book_keeping_size); 172 | memcpy(me + data_ptr_offset + index * data_size, data, data_size); 173 | return BK_OK; 174 | } 175 | 176 | /** 177 | * Copies the element at an index of the array to data. The pointer to the data 178 | * being obtained should point to the data type which this array holds. For 179 | * example, if this array holds integers, the data pointer should be a pointer 180 | * to an integer. Since this data is being copied from the array to the data 181 | * pointer, the pointer only has to be valid when this function is called. 182 | * 183 | * 184 | * @param data the data to copy to 185 | * @param me the array to copy from 186 | * @param index the index to copy from in the array 187 | * 188 | * @return BK_OK if no error 189 | * @return -BK_EINVAL if invalid argument 190 | */ 191 | bk_err array_get(void *const data, array me, const size_t index) 192 | { 193 | size_t element_count; 194 | size_t data_size; 195 | memcpy(&element_count, me + arr_size_offset, book_keeping_size); 196 | if (index >= element_count) { 197 | return -BK_EINVAL; 198 | } 199 | memcpy(&data_size, me + data_size_offset, book_keeping_size); 200 | memcpy(data, me + data_ptr_offset + index * data_size, data_size); 201 | return BK_OK; 202 | } 203 | 204 | /** 205 | * Frees the array memory. Performing further operations after calling this 206 | * function results in undefined behavior. Freeing NULL is legal, and causes 207 | * no operation to be performed. 208 | * 209 | * @param me the array to free from memory 210 | * 211 | * @return NULL 212 | */ 213 | array array_destroy(array me) 214 | { 215 | free(me); 216 | return NULL; 217 | } 218 | -------------------------------------------------------------------------------- /src/include/VERSION: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2022 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | /* 24 | * The Containers library is hosted at: github.com/bkthomps/Containers 25 | * The author is: Bailey Thompson 26 | * This local version is: v1.2.1 27 | */ 28 | -------------------------------------------------------------------------------- /src/include/_bk_defines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_BK_DEFINES_H 24 | #define BKTHOMPS_CONTAINERS_BK_DEFINES_H 25 | 26 | #include 27 | 28 | /* 29 | * Cannot use because the C89 standard does not guarantee all 30 | * of these. These are the same values as the regular linux error codes. 31 | */ 32 | #define BK_OK 0 33 | #define BK_ENOMEM 12 34 | #define BK_EINVAL 22 35 | #define BK_ERANGE 34 36 | 37 | /* Cannot use because it is C99 not C89. */ 38 | #define BK_FALSE 0 39 | #define BK_TRUE (!BK_FALSE) 40 | 41 | typedef int bk_err; 42 | typedef int bk_bool; 43 | 44 | #endif /* BKTHOMPS_CONTAINERS_BK_DEFINES_H */ 45 | -------------------------------------------------------------------------------- /src/include/array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_ARRAY_H 24 | #define BKTHOMPS_CONTAINERS_ARRAY_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The array data structure, which is a static contiguous array. 30 | */ 31 | typedef char *array; 32 | 33 | /* Starting */ 34 | array array_init(size_t element_count, size_t data_size); 35 | 36 | /* Utility */ 37 | size_t array_size(array me); 38 | void array_copy_to_array(void *arr, array me); 39 | void *array_get_data(array me); 40 | bk_err array_add_all(array me, void *arr, size_t size); 41 | 42 | /* Accessing */ 43 | bk_err array_set(array me, size_t index, void *data); 44 | bk_err array_get(void *data, array me, size_t index); 45 | 46 | /* Ending */ 47 | array array_destroy(array me); 48 | 49 | #endif /* BKTHOMPS_CONTAINERS_ARRAY_H */ 50 | -------------------------------------------------------------------------------- /src/include/deque.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_DEQUE_H 24 | #define BKTHOMPS_CONTAINERS_DEQUE_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The deque data structure, which is a doubly-ended queue. 30 | */ 31 | typedef struct internal_deque *deque; 32 | 33 | /* Starting */ 34 | deque deque_init(size_t data_size); 35 | 36 | /* Utility */ 37 | size_t deque_size(deque me); 38 | bk_bool deque_is_empty(deque me); 39 | bk_err deque_trim(deque me); 40 | void deque_copy_to_array(void *arr, deque me); 41 | bk_err deque_add_all(deque me, void *arr, size_t size); 42 | 43 | /* Adding */ 44 | bk_err deque_push_front(deque me, void *data); 45 | bk_err deque_push_back(deque me, void *data); 46 | 47 | /* Removing */ 48 | bk_err deque_pop_front(void *data, deque me); 49 | bk_err deque_pop_back(void *data, deque me); 50 | 51 | /* Setting */ 52 | bk_err deque_set_first(deque me, void *data); 53 | bk_err deque_set_at(deque me, size_t index, void *data); 54 | bk_err deque_set_last(deque me, void *data); 55 | 56 | /* Getting */ 57 | bk_err deque_get_first(void *data, deque me); 58 | bk_err deque_get_at(void *data, deque me, size_t index); 59 | bk_err deque_get_last(void *data, deque me); 60 | 61 | /* Ending */ 62 | bk_err deque_clear(deque me); 63 | deque deque_destroy(deque me); 64 | 65 | #endif /* BKTHOMPS_CONTAINERS_DEQUE_H */ 66 | -------------------------------------------------------------------------------- /src/include/forward_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_FORWARD_LIST_H 24 | #define BKTHOMPS_CONTAINERS_FORWARD_LIST_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The forward_list data structure, which is a singly-linked list. 30 | */ 31 | typedef struct internal_forward_list *forward_list; 32 | 33 | /* Starting */ 34 | forward_list forward_list_init(size_t data_size); 35 | 36 | /* Utility */ 37 | size_t forward_list_size(forward_list me); 38 | bk_bool forward_list_is_empty(forward_list me); 39 | void forward_list_copy_to_array(void *arr, forward_list me); 40 | bk_err forward_list_add_all(forward_list me, void *arr, size_t size); 41 | 42 | /* Adding */ 43 | bk_err forward_list_add_first(forward_list me, void *data); 44 | bk_err forward_list_add_at(forward_list me, size_t index, void *data); 45 | bk_err forward_list_add_last(forward_list me, void *data); 46 | 47 | /* Removing */ 48 | bk_err forward_list_remove_first(forward_list me); 49 | bk_err forward_list_remove_at(forward_list me, size_t index); 50 | bk_err forward_list_remove_last(forward_list me); 51 | 52 | /* Setting */ 53 | bk_err forward_list_set_first(forward_list me, void *data); 54 | bk_err forward_list_set_at(forward_list me, size_t index, void *data); 55 | bk_err forward_list_set_last(forward_list me, void *data); 56 | 57 | /* Getting */ 58 | bk_err forward_list_get_first(void *data, forward_list me); 59 | bk_err forward_list_get_at(void *data, forward_list me, size_t index); 60 | bk_err forward_list_get_last(void *data, forward_list me); 61 | 62 | /* Ending */ 63 | void forward_list_clear(forward_list me); 64 | forward_list forward_list_destroy(forward_list me); 65 | 66 | #endif /* BKTHOMPS_CONTAINERS_FORWARD_LIST_H */ 67 | -------------------------------------------------------------------------------- /src/include/list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_LIST_H 24 | #define BKTHOMPS_CONTAINERS_LIST_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The list data structure, which is a doubly-linked list. 30 | */ 31 | typedef struct internal_list *list; 32 | 33 | /* Starting */ 34 | list list_init(size_t data_size); 35 | 36 | /* Utility */ 37 | size_t list_size(list me); 38 | bk_bool list_is_empty(list me); 39 | void list_copy_to_array(void *arr, list me); 40 | bk_err list_add_all(list me, void *arr, size_t size); 41 | 42 | /* Adding */ 43 | bk_err list_add_first(list me, void *data); 44 | bk_err list_add_at(list me, size_t index, void *data); 45 | bk_err list_add_last(list me, void *data); 46 | 47 | /* Removing */ 48 | bk_err list_remove_first(list me); 49 | bk_err list_remove_at(list me, size_t index); 50 | bk_err list_remove_last(list me); 51 | 52 | /* Setting */ 53 | bk_err list_set_first(list me, void *data); 54 | bk_err list_set_at(list me, size_t index, void *data); 55 | bk_err list_set_last(list me, void *data); 56 | 57 | /* Getting */ 58 | bk_err list_get_first(void *data, list me); 59 | bk_err list_get_at(void *data, list me, size_t index); 60 | bk_err list_get_last(void *data, list me); 61 | 62 | /* Ending */ 63 | void list_clear(list me); 64 | list list_destroy(list me); 65 | 66 | #endif /* BKTHOMPS_CONTAINERS_LIST_H */ 67 | -------------------------------------------------------------------------------- /src/include/map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_MAP_H 24 | #define BKTHOMPS_CONTAINERS_MAP_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The map data structure, which is a collection of key-value pairs, sorted by 30 | * keys, keys are unique. 31 | */ 32 | typedef struct internal_map *map; 33 | 34 | /* Starting */ 35 | map map_init(size_t key_size, size_t value_size, 36 | int (*comparator)(const void *const one, const void *const two)); 37 | 38 | /* Capacity */ 39 | size_t map_size(map me); 40 | bk_bool map_is_empty(map me); 41 | 42 | /* Accessing */ 43 | bk_err map_put(map me, void *key, void *value); 44 | bk_bool map_get(void *value, map me, void *key); 45 | bk_bool map_contains(map me, void *key); 46 | bk_bool map_remove(map me, void *key); 47 | 48 | /* Retrieval */ 49 | void *map_first(map me); 50 | void *map_last(map me); 51 | void *map_lower(map me, void *key); 52 | void *map_higher(map me, void *key); 53 | void *map_floor(map me, void *key); 54 | void *map_ceiling(map me, void *key); 55 | 56 | /* Ending */ 57 | void map_clear(map me); 58 | map map_destroy(map me); 59 | 60 | #endif /* BKTHOMPS_CONTAINERS_MAP_H */ 61 | -------------------------------------------------------------------------------- /src/include/multimap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_MULTIMAP_H 24 | #define BKTHOMPS_CONTAINERS_MULTIMAP_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The multimap data structure, which is a collection of key-value pairs, sorted 30 | * by keys. 31 | */ 32 | typedef struct internal_multimap *multimap; 33 | 34 | /* Starting */ 35 | multimap multimap_init(size_t key_size, size_t value_size, 36 | int (*key_comparator)(const void *const one, 37 | const void *const two), 38 | int (*value_comparator)(const void *const one, 39 | const void *const two)); 40 | 41 | /* Capacity */ 42 | size_t multimap_size(multimap me); 43 | bk_bool multimap_is_empty(multimap me); 44 | 45 | /* Accessing */ 46 | bk_err multimap_put(multimap me, void *key, void *value); 47 | void multimap_get_start(multimap me, void *key); 48 | bk_bool multimap_get_next(void *value, multimap me); 49 | size_t multimap_count(multimap me, void *key); 50 | bk_bool multimap_contains(multimap me, void *key); 51 | bk_bool multimap_remove(multimap me, void *key, void *value); 52 | bk_bool multimap_remove_all(multimap me, void *key); 53 | 54 | /* Retrieval */ 55 | void *multimap_first(multimap me); 56 | void *multimap_last(multimap me); 57 | void *multimap_lower(multimap me, void *key); 58 | void *multimap_higher(multimap me, void *key); 59 | void *multimap_floor(multimap me, void *key); 60 | void *multimap_ceiling(multimap me, void *key); 61 | 62 | /* Ending */ 63 | void multimap_clear(multimap me); 64 | multimap multimap_destroy(multimap me); 65 | 66 | #endif /* BKTHOMPS_CONTAINERS_MULTIMAP_H */ 67 | -------------------------------------------------------------------------------- /src/include/multiset.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_MULTISET_H 24 | #define BKTHOMPS_CONTAINERS_MULTISET_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The multiset data structure, which is a collection of key-value pairs, sorted 30 | * by keys, keys are unique 31 | */ 32 | typedef struct internal_multiset *multiset; 33 | 34 | /* Starting */ 35 | multiset multiset_init(size_t key_size, 36 | int (*comparator)(const void *const one, 37 | const void *const two)); 38 | 39 | /* Capacity */ 40 | size_t multiset_size(multiset me); 41 | bk_bool multiset_is_empty(multiset me); 42 | 43 | /* Accessing */ 44 | bk_err multiset_put(multiset me, void *key); 45 | size_t multiset_count(multiset me, void *key); 46 | bk_bool multiset_contains(multiset me, void *key); 47 | bk_bool multiset_remove(multiset me, void *key); 48 | bk_bool multiset_remove_all(multiset me, void *key); 49 | 50 | /* Retrieval */ 51 | void *multiset_first(multiset me); 52 | void *multiset_last(multiset me); 53 | void *multiset_lower(multiset me, void *key); 54 | void *multiset_higher(multiset me, void *key); 55 | void *multiset_floor(multiset me, void *key); 56 | void *multiset_ceiling(multiset me, void *key); 57 | 58 | /* Ending */ 59 | void multiset_clear(multiset me); 60 | multiset multiset_destroy(multiset me); 61 | 62 | #endif /* BKTHOMPS_CONTAINERS_MULTISET_H */ 63 | -------------------------------------------------------------------------------- /src/include/priority_queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_PRIORITY_QUEUE_H 24 | #define BKTHOMPS_CONTAINERS_PRIORITY_QUEUE_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The priority_queue data structure, which adapts a container to provide a 30 | * priority queue. Adapts the vector container. 31 | */ 32 | typedef struct internal_priority_queue *priority_queue; 33 | 34 | /* Starting */ 35 | priority_queue priority_queue_init(size_t data_size, 36 | int (*comparator)(const void *const one, 37 | const void *const two)); 38 | 39 | /* Utility */ 40 | size_t priority_queue_size(priority_queue me); 41 | bk_bool priority_queue_is_empty(priority_queue me); 42 | 43 | /* Adding */ 44 | bk_err priority_queue_push(priority_queue me, void *data); 45 | 46 | /* Removing */ 47 | bk_bool priority_queue_pop(void *data, priority_queue me); 48 | 49 | /* Getting */ 50 | bk_bool priority_queue_front(void *data, priority_queue me); 51 | 52 | /* Ending */ 53 | bk_err priority_queue_clear(priority_queue me); 54 | priority_queue priority_queue_destroy(priority_queue me); 55 | 56 | #endif /* BKTHOMPS_CONTAINERS_PRIORITY_QUEUE_H */ 57 | -------------------------------------------------------------------------------- /src/include/queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_QUEUE_H 24 | #define BKTHOMPS_CONTAINERS_QUEUE_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The queue data structure, which adapts a container to provide a queue 30 | * (first-in first-out). Adapts the deque container. 31 | */ 32 | typedef struct internal_deque *queue; 33 | 34 | /* Starting */ 35 | queue queue_init(size_t data_size); 36 | 37 | /* Utility */ 38 | size_t queue_size(queue me); 39 | bk_bool queue_is_empty(queue me); 40 | bk_err queue_trim(queue me); 41 | void queue_copy_to_array(void *arr, queue me); 42 | 43 | /* Adding */ 44 | bk_err queue_push(queue me, void *data); 45 | 46 | /* Removing */ 47 | bk_bool queue_pop(void *data, queue me); 48 | 49 | /* Getting */ 50 | bk_bool queue_front(void *data, queue me); 51 | bk_bool queue_back(void *data, queue me); 52 | 53 | /* Ending */ 54 | bk_err queue_clear(queue me); 55 | queue queue_destroy(queue me); 56 | 57 | #endif /* BKTHOMPS_CONTAINERS_QUEUE_H */ 58 | -------------------------------------------------------------------------------- /src/include/set.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_SET_H 24 | #define BKTHOMPS_CONTAINERS_SET_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The set data structure, which is a collection of unique keys, sorted by keys. 30 | */ 31 | typedef struct internal_set *set; 32 | 33 | /* Starting */ 34 | set set_init(size_t key_size, 35 | int (*comparator)(const void *const one, const void *const two)); 36 | 37 | /* Capacity */ 38 | size_t set_size(set me); 39 | bk_bool set_is_empty(set me); 40 | 41 | /* Accessing */ 42 | bk_err set_put(set me, void *key); 43 | bk_bool set_contains(set me, void *key); 44 | bk_bool set_remove(set me, void *key); 45 | 46 | /* Retrieval */ 47 | void *set_first(set me); 48 | void *set_last(set me); 49 | void *set_lower(set me, void *key); 50 | void *set_higher(set me, void *key); 51 | void *set_floor(set me, void *key); 52 | void *set_ceiling(set me, void *key); 53 | 54 | /* Ending */ 55 | void set_clear(set me); 56 | set set_destroy(set me); 57 | 58 | #endif /* BKTHOMPS_CONTAINERS_SET_H */ 59 | -------------------------------------------------------------------------------- /src/include/stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_STACK_H 24 | #define BKTHOMPS_CONTAINERS_STACK_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The stack data structure, which adapts a container to provide a stack 30 | * (last-in first-out). Adapts the deque container. 31 | */ 32 | typedef struct internal_deque *stack; 33 | 34 | /* Starting */ 35 | stack stack_init(size_t data_size); 36 | 37 | /* Utility */ 38 | size_t stack_size(stack me); 39 | bk_bool stack_is_empty(stack me); 40 | bk_err stack_trim(stack me); 41 | void stack_copy_to_array(void *arr, stack me); 42 | 43 | /* Adding */ 44 | bk_err stack_push(stack me, void *data); 45 | 46 | /* Removing */ 47 | bk_bool stack_pop(void *data, stack me); 48 | 49 | /* Getting */ 50 | bk_bool stack_top(void *data, stack me); 51 | 52 | /* Ending */ 53 | bk_err stack_clear(stack me); 54 | stack stack_destroy(stack me); 55 | 56 | #endif /* BKTHOMPS_CONTAINERS_STACK_H */ 57 | -------------------------------------------------------------------------------- /src/include/unordered_map.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_UNORDERED_MAP_H 24 | #define BKTHOMPS_CONTAINERS_UNORDERED_MAP_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The unordered_map data structure, which is a collection of key-value pairs, 30 | * hashed by keys, keys are unique 31 | */ 32 | typedef struct internal_unordered_map *unordered_map; 33 | 34 | /* Starting */ 35 | unordered_map unordered_map_init(size_t key_size, 36 | size_t value_size, 37 | unsigned long (*hash)(const void *const key), 38 | int (*comparator)(const void *const one, 39 | const void *const two)); 40 | 41 | /* Utility */ 42 | bk_err unordered_map_rehash(unordered_map me); 43 | size_t unordered_map_size(unordered_map me); 44 | bk_bool unordered_map_is_empty(unordered_map me); 45 | 46 | /* Accessing */ 47 | bk_err unordered_map_put(unordered_map me, void *key, void *value); 48 | bk_bool unordered_map_get(void *value, unordered_map me, void *key); 49 | bk_bool unordered_map_contains(unordered_map me, void *key); 50 | bk_bool unordered_map_remove(unordered_map me, void *key); 51 | 52 | /* Ending */ 53 | bk_err unordered_map_clear(unordered_map me); 54 | unordered_map unordered_map_destroy(unordered_map me); 55 | 56 | #endif /* BKTHOMPS_CONTAINERS_UNORDERED_MAP_H */ 57 | -------------------------------------------------------------------------------- /src/include/unordered_multimap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_UNORDERED_MULTIMAP_H 24 | #define BKTHOMPS_CONTAINERS_UNORDERED_MULTIMAP_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The unordered_multimap data structure, which is a collection of key-value 30 | * pairs, hashed by keys. 31 | */ 32 | typedef struct internal_unordered_multimap *unordered_multimap; 33 | 34 | /* Starting */ 35 | unordered_multimap 36 | unordered_multimap_init(size_t key_size, 37 | size_t value_size, 38 | unsigned long (*hash)(const void *const key), 39 | int (*key_comparator)(const void *const one, 40 | const void *const two), 41 | int (*value_comparator)(const void *const one, 42 | const void *const two)); 43 | 44 | /* Utility */ 45 | bk_err unordered_multimap_rehash(unordered_multimap me); 46 | size_t unordered_multimap_size(unordered_multimap me); 47 | bk_bool unordered_multimap_is_empty(unordered_multimap me); 48 | 49 | /* Accessing */ 50 | bk_err unordered_multimap_put(unordered_multimap me, void *key, void *value); 51 | void unordered_multimap_get_start(unordered_multimap me, void *key); 52 | bk_bool unordered_multimap_get_next(void *value, unordered_multimap me); 53 | size_t unordered_multimap_count(unordered_multimap me, void *key); 54 | bk_bool unordered_multimap_contains(unordered_multimap me, void *key); 55 | bk_bool unordered_multimap_remove(unordered_multimap me, 56 | void *key, void *value); 57 | bk_bool unordered_multimap_remove_all(unordered_multimap me, void *key); 58 | 59 | /* Ending */ 60 | bk_err unordered_multimap_clear(unordered_multimap me); 61 | unordered_multimap unordered_multimap_destroy(unordered_multimap me); 62 | 63 | #endif /* BKTHOMPS_CONTAINERS_UNORDERED_MULTIMAP_H */ 64 | -------------------------------------------------------------------------------- /src/include/unordered_multiset.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_UNORDERED_MULTISET_H 24 | #define BKTHOMPS_CONTAINERS_UNORDERED_MULTISET_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The unordered_multiset data structure, which is a collection of keys, hashed 30 | * by keys. 31 | */ 32 | typedef struct internal_unordered_multiset *unordered_multiset; 33 | 34 | /* Starting */ 35 | unordered_multiset 36 | unordered_multiset_init(size_t key_size, 37 | unsigned long (*hash)(const void *const key), 38 | int (*comparator)(const void *const one, 39 | const void *const two)); 40 | 41 | /* Utility */ 42 | bk_err unordered_multiset_rehash(unordered_multiset me); 43 | size_t unordered_multiset_size(unordered_multiset me); 44 | bk_bool unordered_multiset_is_empty(unordered_multiset me); 45 | 46 | /* Accessing */ 47 | bk_err unordered_multiset_put(unordered_multiset me, void *key); 48 | size_t unordered_multiset_count(unordered_multiset me, void *key); 49 | bk_bool unordered_multiset_contains(unordered_multiset me, void *key); 50 | bk_bool unordered_multiset_remove(unordered_multiset me, void *key); 51 | bk_bool unordered_multiset_remove_all(unordered_multiset me, void *key); 52 | 53 | /* Ending */ 54 | bk_err unordered_multiset_clear(unordered_multiset me); 55 | unordered_multiset unordered_multiset_destroy(unordered_multiset me); 56 | 57 | #endif /* BKTHOMPS_CONTAINERS_UNORDERED_MULTISET_H */ 58 | -------------------------------------------------------------------------------- /src/include/unordered_set.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_UNORDERED_SET_H 24 | #define BKTHOMPS_CONTAINERS_UNORDERED_SET_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The unordered_set data structure, which is a collection of unique keys, 30 | * hashed by keys. 31 | */ 32 | typedef struct internal_unordered_set *unordered_set; 33 | 34 | /* Starting */ 35 | unordered_set unordered_set_init(size_t key_size, 36 | unsigned long (*hash)(const void *const key), 37 | int (*comparator)(const void *const one, 38 | const void *const two)); 39 | 40 | /* Utility */ 41 | bk_err unordered_set_rehash(unordered_set me); 42 | size_t unordered_set_size(unordered_set me); 43 | bk_bool unordered_set_is_empty(unordered_set me); 44 | 45 | /* Accessing */ 46 | bk_err unordered_set_put(unordered_set me, void *key); 47 | bk_bool unordered_set_contains(unordered_set me, void *key); 48 | bk_bool unordered_set_remove(unordered_set me, void *key); 49 | 50 | /* Ending */ 51 | bk_err unordered_set_clear(unordered_set me); 52 | unordered_set unordered_set_destroy(unordered_set me); 53 | 54 | #endif /* BKTHOMPS_CONTAINERS_UNORDERED_SET_H */ 55 | -------------------------------------------------------------------------------- /src/include/vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #ifndef BKTHOMPS_CONTAINERS_VECTOR_H 24 | #define BKTHOMPS_CONTAINERS_VECTOR_H 25 | 26 | #include "_bk_defines.h" 27 | 28 | /** 29 | * The vector data structure, which is a dynamic contiguous array. 30 | */ 31 | typedef struct internal_vector *vector; 32 | 33 | /* Starting */ 34 | vector vector_init(size_t data_size); 35 | 36 | /* Utility */ 37 | size_t vector_size(vector me); 38 | size_t vector_capacity(vector me); 39 | bk_bool vector_is_empty(vector me); 40 | bk_err vector_reserve(vector me, size_t size); 41 | bk_err vector_trim(vector me); 42 | void vector_copy_to_array(void *arr, vector me); 43 | void *vector_get_data(vector me); 44 | bk_err vector_add_all(vector me, void *arr, size_t size); 45 | 46 | /* Adding */ 47 | bk_err vector_add_first(vector me, void *data); 48 | bk_err vector_add_at(vector me, size_t index, void *data); 49 | bk_err vector_add_last(vector me, void *data); 50 | 51 | /* Removing */ 52 | bk_err vector_remove_first(vector me); 53 | bk_err vector_remove_at(vector me, size_t index); 54 | bk_err vector_remove_last(vector me); 55 | 56 | /* Setting */ 57 | bk_err vector_set_first(vector me, void *data); 58 | bk_err vector_set_at(vector me, size_t index, void *data); 59 | bk_err vector_set_last(vector me, void *data); 60 | 61 | /* Getting */ 62 | bk_err vector_get_first(void *data, vector me); 63 | bk_err vector_get_at(void *data, vector me, size_t index); 64 | bk_err vector_get_last(void *data, vector me); 65 | 66 | /* Ending */ 67 | bk_err vector_clear(vector me); 68 | vector vector_destroy(vector me); 69 | 70 | #endif /* BKTHOMPS_CONTAINERS_VECTOR_H */ 71 | -------------------------------------------------------------------------------- /src/priority_queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2022 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "include/vector.h" 25 | #include "include/priority_queue.h" 26 | 27 | struct internal_priority_queue { 28 | size_t data_size; 29 | int (*comparator)(const void *const one, const void *const two); 30 | vector data; 31 | }; 32 | 33 | /** 34 | * Initializes a priority queue. 35 | * 36 | * @param data_size the size of the data in the priority queue; must be 37 | * positive 38 | * @param comparator the priority comparator function; must not be NULL 39 | * 40 | * @return the newly-initialized priority queue, or NULL if it was not 41 | * successfully initialized due to either invalid input arguments or 42 | * memory allocation error 43 | */ 44 | priority_queue priority_queue_init(const size_t data_size, 45 | int (*comparator)(const void *const, 46 | const void *const)) 47 | { 48 | struct internal_priority_queue *init; 49 | if (data_size == 0 || !comparator) { 50 | return NULL; 51 | } 52 | init = malloc(sizeof *init); 53 | if (!init) { 54 | return NULL; 55 | } 56 | init->data_size = data_size; 57 | init->comparator = comparator; 58 | init->data = vector_init(data_size); 59 | if (!init->data) { 60 | free(init); 61 | return NULL; 62 | } 63 | return init; 64 | } 65 | 66 | /** 67 | * Gets the size of the priority queue. 68 | * 69 | * @param me the priority queue to check 70 | * 71 | * @return the size of the priority queue 72 | */ 73 | size_t priority_queue_size(priority_queue me) 74 | { 75 | return vector_size(me->data); 76 | } 77 | 78 | /** 79 | * Determines whether or not the priority queue is empty. 80 | * 81 | * @param me the priority queue to check 82 | * 83 | * @return BK_TRUE if the priority queue is empty, otherwise BK_FALSE 84 | */ 85 | bk_bool priority_queue_is_empty(priority_queue me) 86 | { 87 | return vector_is_empty(me->data); 88 | } 89 | 90 | /** 91 | * Adds an element to the priority queue. The pointer to the data being passed 92 | * in should point to the data type which this priority queue holds. For 93 | * example, if this priority queue holds integers, the data pointer should be a 94 | * pointer to an integer. Since the data is being copied, the pointer only has 95 | * to be valid when this function is called. 96 | * 97 | * @param me the priority queue to add an element to 98 | * @param data the data to add to the queue 99 | * 100 | * @return BK_OK if no error 101 | * @return -BK_ENOMEM if out of memory 102 | * @return -BK_ERANGE if size has reached representable limit 103 | */ 104 | bk_err priority_queue_push(priority_queue me, void *const data) 105 | { 106 | bk_err rc; 107 | char *vector_storage; 108 | size_t index; 109 | size_t parent_index; 110 | char *data_index; 111 | char *data_parent_index; 112 | char *const temp = malloc(me->data_size); 113 | if (!temp) { 114 | return -BK_ENOMEM; 115 | } 116 | rc = vector_add_last(me->data, data); 117 | if (rc != BK_OK) { 118 | free(temp); 119 | return rc; 120 | } 121 | vector_storage = vector_get_data(me->data); 122 | index = vector_size(me->data) - 1; 123 | parent_index = (index - 1) / 2; 124 | data_index = vector_storage + index * me->data_size; 125 | data_parent_index = vector_storage + parent_index * me->data_size; 126 | while (index > 0 && me->comparator(data_index, data_parent_index) > 0) { 127 | memcpy(temp, data_parent_index, me->data_size); 128 | memcpy(data_parent_index, data_index, me->data_size); 129 | memcpy(data_index, temp, me->data_size); 130 | index = parent_index; 131 | parent_index = (index - 1) / 2; 132 | data_index = vector_storage + index * me->data_size; 133 | data_parent_index = vector_storage + parent_index * me->data_size; 134 | } 135 | free(temp); 136 | return BK_OK; 137 | } 138 | 139 | /** 140 | * Removes the highest priority element from the priority queue. The pointer to 141 | * the data being obtained should point to the data type which this priority 142 | * queue holds. For example, if this priority queue holds integers, the data 143 | * pointer should be a pointer to an integer. Since this data is being copied 144 | * from the array to the data pointer, the pointer only has to be valid when 145 | * this function is called. 146 | * 147 | * @param data the data to have copied from the priority queue 148 | * @param me the priority queue to pop the next element from 149 | * 150 | * @return BK_TRUE if the priority queue contained elements, otherwise BK_FALSE 151 | */ 152 | bk_bool priority_queue_pop(void *const data, priority_queue me) 153 | { 154 | char *vector_storage; 155 | size_t size; 156 | char *temp; 157 | size_t index; 158 | size_t left_index; 159 | size_t right_index; 160 | char *data_index; 161 | char *data_left_index; 162 | char *data_right_index; 163 | const bk_err rc = vector_get_first(data, me->data); 164 | if (rc != BK_OK) { 165 | return BK_FALSE; 166 | } 167 | vector_storage = vector_get_data(me->data); 168 | size = vector_size(me->data) - 1; 169 | temp = vector_storage + size * me->data_size; 170 | memcpy(vector_storage, temp, me->data_size); 171 | left_index = 1; 172 | right_index = 2; 173 | data_index = vector_storage; 174 | data_left_index = vector_storage + left_index * me->data_size; 175 | data_right_index = vector_storage + right_index * me->data_size; 176 | for (;;) { 177 | if (right_index < size && 178 | me->comparator(data_right_index, data_left_index) > 0 && 179 | me->comparator(data_right_index, data_index) > 0) { 180 | /* Swap parent and right child then continue down right child. */ 181 | memcpy(temp, data_index, me->data_size); 182 | memcpy(data_index, data_right_index, me->data_size); 183 | memcpy(data_right_index, temp, me->data_size); 184 | index = right_index; 185 | } else if (left_index < size && 186 | me->comparator(data_left_index, data_index) > 0) { 187 | /* Swap parent and left child then continue down left child. */ 188 | memcpy(temp, data_index, me->data_size); 189 | memcpy(data_index, data_left_index, me->data_size); 190 | memcpy(data_left_index, temp, me->data_size); 191 | index = left_index; 192 | } else { 193 | break; 194 | } 195 | left_index = 2 * index + 1; 196 | right_index = 2 * index + 2; 197 | data_index = vector_storage + index * me->data_size; 198 | data_left_index = vector_storage + left_index * me->data_size; 199 | data_right_index = vector_storage + right_index * me->data_size; 200 | } 201 | vector_remove_last(me->data); 202 | return BK_TRUE; 203 | } 204 | 205 | /** 206 | * Gets the highest priority element in the priority queue. The pointer to the 207 | * data being obtained should point to the data type which this priority queue 208 | * holds. For example, if this priority queue holds integers, the data pointer 209 | * should be a pointer to an integer. Since this data is being copied from the 210 | * array to the data pointer, the pointer only has to be valid when this 211 | * function is called. 212 | * 213 | * @param data the out copy of the highest priority element in the priority 214 | * queue 215 | * @param me the priority queue to copy from 216 | * 217 | * @return BK_TRUE if the priority queue contained elements, otherwise BK_FALSE 218 | */ 219 | bk_bool priority_queue_front(void *const data, priority_queue me) 220 | { 221 | return vector_get_first(data, me->data) == 0; 222 | } 223 | 224 | /** 225 | * Clears the elements from the priority queue. 226 | * 227 | * @param me the priority queue to clear 228 | * 229 | * @return BK_OK if no error 230 | * @return -BK_ENOMEM if out of memory 231 | */ 232 | bk_err priority_queue_clear(priority_queue me) 233 | { 234 | return vector_clear(me->data); 235 | } 236 | 237 | /** 238 | * Frees the priority queue memory. Performing further operations after calling 239 | * this function results in undefined behavior. Freeing NULL is legal, and 240 | * causes no operation to be performed. 241 | * 242 | * @param me the priority queue to free from memory 243 | * 244 | * @return NULL 245 | */ 246 | priority_queue priority_queue_destroy(priority_queue me) 247 | { 248 | if (me) { 249 | vector_destroy(me->data); 250 | free(me); 251 | } 252 | return NULL; 253 | } 254 | -------------------------------------------------------------------------------- /src/queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "include/deque.h" 24 | #include "include/queue.h" 25 | 26 | /** 27 | * Initializes a queue. 28 | * 29 | * @param data_size the size of each element; must be positive 30 | * 31 | * @return the newly-initialized queue, or NULL if it was not successfully 32 | * initialized due to either invalid input arguments or memory 33 | * allocation error 34 | */ 35 | queue queue_init(const size_t data_size) 36 | { 37 | return deque_init(data_size); 38 | } 39 | 40 | /** 41 | * Determines the size of the queue. 42 | * 43 | * @param me the queue to get size of 44 | * 45 | * @return the queue size 46 | */ 47 | size_t queue_size(queue me) 48 | { 49 | return deque_size(me); 50 | } 51 | 52 | /** 53 | * Determines if the queue is empty. The queue is empty if it contains no 54 | * elements. 55 | * 56 | * @param me the queue to check if empty 57 | * 58 | * @return BK_TRUE if the queue is empty, otherwise BK_FALSE 59 | */ 60 | bk_bool queue_is_empty(queue me) 61 | { 62 | return deque_is_empty(me); 63 | } 64 | 65 | /** 66 | * Frees the unused memory in the queue. 67 | * 68 | * @param me the queue to trim 69 | * 70 | * @return BK_OK if no error 71 | * @return -BK_ENOMEM if out of memory 72 | */ 73 | bk_err queue_trim(queue me) 74 | { 75 | return deque_trim(me); 76 | } 77 | 78 | /** 79 | * Copies the queue to an array. Since it is a copy, the array may be modified 80 | * without causing side effects to the queue data structure. Memory is not 81 | * allocated, thus the array being used for the copy must be allocated before 82 | * this function is called. 83 | * 84 | * @param arr the initialized array to copy the queue to 85 | * @param me the queue to copy to the array 86 | */ 87 | void queue_copy_to_array(void *const arr, queue me) 88 | { 89 | deque_copy_to_array(arr, me); 90 | } 91 | 92 | /** 93 | * Adds an element to the queue. The pointer to the data being passed in should 94 | * point to the data type which this queue holds. For example, if this queue 95 | * holds integers, the data pointer should be a pointer to an integer. Since the 96 | * data is being copied, the pointer only has to be valid when this function is 97 | * called. 98 | * 99 | * @param me the queue to add an element to 100 | * @param data the data to add to the queue 101 | * 102 | * @return BK_OK if no error 103 | * @return -BK_ENOMEM if out of memory 104 | * @return -BK_ERANGE if size has reached representable limit 105 | */ 106 | bk_err queue_push(queue me, void *const data) 107 | { 108 | return deque_push_back(me, data); 109 | } 110 | 111 | /** 112 | * Removes the next element in the queue and copies the data. The pointer to the 113 | * data being obtained should point to the data type which this queue holds. For 114 | * example, if this queue holds integers, the data pointer should be a pointer 115 | * to an integer. Since this data is being copied from the array to the data 116 | * pointer, the pointer only has to be valid when this function is called. 117 | * 118 | * @param data the data to have copied from the queue 119 | * @param me the queue to pop the next element from 120 | * 121 | * @return BK_TRUE if the queue contained elements, otherwise BK_FALSE 122 | */ 123 | bk_bool queue_pop(void *const data, queue me) 124 | { 125 | return deque_pop_front(data, me) == 0; 126 | } 127 | 128 | /** 129 | * Gets the front element of the queue. The pointer to the data being obtained 130 | * should point to the data type which this queue holds. For example, if this 131 | * queue holds integers, the data pointer should be a pointer to an integer. 132 | * Since this data is being copied from the array to the data pointer, the 133 | * pointer only has to be valid when this function is called. 134 | * 135 | * @param data the copy of the front element of the queue 136 | * @param me the queue to copy from 137 | * 138 | * @return BK_TRUE if the queue contained elements, otherwise BK_FALSE 139 | */ 140 | bk_bool queue_front(void *const data, queue me) 141 | { 142 | return deque_get_first(data, me) == 0; 143 | } 144 | 145 | /** 146 | * Gets the back element of the queue. The pointer to the data being obtained 147 | * should point to the data type which this queue holds. For example, if this 148 | * queue holds integers, the data pointer should be a pointer to an integer. 149 | * Since this data is being copied from the array to the data pointer, the 150 | * pointer only has to be valid when this function is called. 151 | * 152 | * @param data the copy of the back element of the queue 153 | * @param me the queue to copy from 154 | * 155 | * @return BK_TRUE if the queue contained elements, otherwise BK_FALSE 156 | */ 157 | bk_bool queue_back(void *const data, queue me) 158 | { 159 | return deque_get_last(data, me) == 0; 160 | } 161 | 162 | /** 163 | * Clears the queue and sets it to the original state from initialization. 164 | * 165 | * @param me the queue to clear 166 | * 167 | * @return BK_OK if no error 168 | * @return -BK_ENOMEM if out of memory 169 | */ 170 | bk_err queue_clear(queue me) 171 | { 172 | return deque_clear(me); 173 | } 174 | 175 | /** 176 | * Destroys the queue. Performing further operations after calling this function 177 | * results in undefined behavior. Freeing NULL is legal, and causes no operation 178 | * to be performed. 179 | * 180 | * @param me the queue to destroy 181 | * 182 | * @return NULL 183 | */ 184 | queue queue_destroy(queue me) 185 | { 186 | return deque_destroy(me); 187 | } 188 | -------------------------------------------------------------------------------- /src/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2020 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include "include/deque.h" 24 | #include "include/stack.h" 25 | 26 | /** 27 | * Initializes a stack. 28 | * 29 | * @param data_size the size of each data element in the stack; must be 30 | * positive 31 | * 32 | * @return the newly-initialized stack, or NULL if it was not successfully 33 | * initialized due to either invalid input arguments or memory 34 | * allocation error 35 | */ 36 | stack stack_init(const size_t data_size) 37 | { 38 | return deque_init(data_size); 39 | } 40 | 41 | /** 42 | * Determines the size of the stack. 43 | * 44 | * @param me the stack to check size of 45 | * 46 | * @return the size of the stack 47 | */ 48 | size_t stack_size(stack me) 49 | { 50 | return deque_size(me); 51 | } 52 | 53 | /** 54 | * Determines if the stack is empty, meaning it contains no elements. 55 | * 56 | * @param me the stack to check if empty 57 | * 58 | * @return BK_TRUE if the stack is empty, otherwise BK_FALSE 59 | */ 60 | bk_bool stack_is_empty(stack me) 61 | { 62 | return deque_is_empty(me); 63 | } 64 | 65 | /** 66 | * Frees unused memory from the stack. 67 | * 68 | * @param me the stack to trim 69 | * 70 | * @return BK_OK if no error 71 | * @return -BK_ENOMEM if out of memory 72 | */ 73 | bk_err stack_trim(stack me) 74 | { 75 | return deque_trim(me); 76 | } 77 | 78 | /** 79 | * Copies the stack to an array. Since it is a copy, the array may be modified 80 | * without causing side effects to the stack data structure. Memory is not 81 | * allocated, thus the array being used for the copy must be allocated before 82 | * this function is called. 83 | * 84 | * @param arr the initialized array to copy the stack to 85 | * @param me the stack to copy to the array 86 | */ 87 | void stack_copy_to_array(void *const arr, stack me) 88 | { 89 | deque_copy_to_array(arr, me); 90 | } 91 | 92 | /** 93 | * Adds an element to the top of the stack. The pointer to the data being passed 94 | * in should point to the data type which this stack holds. For example, if this 95 | * stack holds integers, the data pointer should be a pointer to an integer. 96 | * Since the data is being copied, the pointer only has to be valid when this 97 | * function is called. 98 | * 99 | * @param me the stack to add an element to 100 | * @param data the data to add to the stack 101 | * 102 | * @return BK_OK if no error 103 | * @return -BK_ENOMEM if out of memory 104 | * @return -BK_ERANGE if size has reached representable limit 105 | */ 106 | bk_err stack_push(stack me, void *const data) 107 | { 108 | return deque_push_back(me, data); 109 | } 110 | 111 | /** 112 | * Removes the top element of the stack, and copies the data which is being 113 | * removed. The pointer to the data being obtained should point to the data type 114 | * which this stack holds. For example, if this stack holds integers, the data 115 | * pointer should be a pointer to an integer. Since this data is being copied 116 | * from the array to the data pointer, the pointer only has to be valid when 117 | * this function is called. 118 | * 119 | * @param data the copy of the element being removed 120 | * @param me the stack to remove the top element from 121 | * 122 | * @return BK_TRUE if the stack contained elements, otherwise BK_FALSE 123 | */ 124 | bk_bool stack_pop(void *const data, stack me) 125 | { 126 | return deque_pop_back(data, me) == 0; 127 | } 128 | 129 | /** 130 | * Copies the top element of the stack. The pointer to the data being obtained 131 | * should point to the data type which this stack holds. For example, if this 132 | * stack holds integers, the data pointer should be a pointer to an integer. 133 | * Since this data is being copied from the array to the data pointer, the 134 | * pointer only has to be valid when this function is called. 135 | * 136 | * @param data the copy of the top element of the stack 137 | * @param me the stack to copy from 138 | * 139 | * @return BK_TRUE if the stack contained elements, otherwise BK_FALSE 140 | */ 141 | bk_bool stack_top(void *const data, stack me) 142 | { 143 | return deque_get_last(data, me) == 0; 144 | } 145 | 146 | /** 147 | * Clears the stack and sets it to the state from original initialization. 148 | * 149 | * @param me the stack to clear 150 | * 151 | * @return BK_OK if no error 152 | * @return -BK_ENOMEM if out of memory 153 | */ 154 | bk_err stack_clear(stack me) 155 | { 156 | return deque_clear(me); 157 | } 158 | 159 | /** 160 | * Frees the stack memory. Performing further operations after calling this 161 | * function results in undefined behavior. Freeing NULL is legal, and causes 162 | * no operation to be performed. 163 | * 164 | * @param me the stack to destroy 165 | * 166 | * @return NULL 167 | */ 168 | stack stack_destroy(stack me) 169 | { 170 | return deque_destroy(me); 171 | } 172 | -------------------------------------------------------------------------------- /src/unordered_set.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017-2022 Bailey Thompson 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | * SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "include/unordered_set.h" 25 | 26 | #define BKTHOMPS_U_SET_STARTING_BUCKETS 16 27 | #define BKTHOMPS_U_SET_RESIZE_AT 0.75 28 | #define BKTHOMPS_U_SET_RESIZE_RATIO 2 29 | 30 | struct internal_unordered_set { 31 | size_t key_size; 32 | size_t size; 33 | size_t capacity; 34 | unsigned long (*hash)(const void *const key); 35 | int (*comparator)(const void *const one, const void *const two); 36 | char **buckets; 37 | }; 38 | 39 | static const size_t ptr_size = sizeof(char *); 40 | static const size_t hash_size = sizeof(unsigned long); 41 | static const size_t node_next_offset = 0; 42 | static const size_t node_hash_offset = sizeof(char *); 43 | static const size_t node_key_offset = sizeof(char *) + sizeof(unsigned long); 44 | 45 | /* 46 | * Gets the hash by first calling the user-defined hash, and then using a 47 | * second hash to prevent hashing clusters if the user-defined hash is 48 | * sub-optimal. 49 | */ 50 | static unsigned long unordered_set_hash(unordered_set me, const void *const key) 51 | { 52 | unsigned long hash = me->hash(key); 53 | hash ^= (hash >> 20UL) ^ (hash >> 12UL); 54 | return hash ^ (hash >> 7UL) ^ (hash >> 4UL); 55 | } 56 | 57 | /** 58 | * Initializes an unordered set. 59 | * 60 | * @param key_size the size of each key in the unordered set; must be 61 | * positive 62 | * @param hash the hash function which computes the hash from the key; 63 | * must not be NULL 64 | * @param comparator the comparator function which compares two keys; must not 65 | * be NULL 66 | * 67 | * @return the newly-initialized unordered set, or NULL if it was not 68 | * successfully initialized due to either invalid input arguments or 69 | * memory allocation error 70 | */ 71 | unordered_set unordered_set_init(const size_t key_size, 72 | unsigned long (*hash)(const void *const), 73 | int (*comparator)(const void *const, 74 | const void *const)) 75 | { 76 | struct internal_unordered_set *init; 77 | if (key_size == 0 || !hash || !comparator) { 78 | return NULL; 79 | } 80 | if (node_key_offset + key_size < node_key_offset) { 81 | return NULL; 82 | } 83 | init = malloc(sizeof *init); 84 | if (!init) { 85 | return NULL; 86 | } 87 | init->key_size = key_size; 88 | init->hash = hash; 89 | init->comparator = comparator; 90 | init->size = 0; 91 | init->capacity = BKTHOMPS_U_SET_STARTING_BUCKETS; 92 | init->buckets = calloc(BKTHOMPS_U_SET_STARTING_BUCKETS, ptr_size); 93 | if (!init->buckets) { 94 | free(init); 95 | return NULL; 96 | } 97 | return init; 98 | } 99 | 100 | /* 101 | * Adds the specified node to the set. 102 | */ 103 | static void unordered_set_add_item(unordered_set me, char *const add) 104 | { 105 | char *traverse; 106 | char *traverse_next; 107 | unsigned long hash; 108 | size_t index; 109 | memcpy(&hash, add + node_hash_offset, hash_size); 110 | index = hash % me->capacity; 111 | memset(add + node_next_offset, 0, ptr_size); 112 | if (!me->buckets[index]) { 113 | me->buckets[index] = add; 114 | return; 115 | } 116 | traverse = me->buckets[index]; 117 | memcpy(&traverse_next, traverse + node_next_offset, ptr_size); 118 | while (traverse_next) { 119 | traverse = traverse_next; 120 | memcpy(&traverse_next, traverse + node_next_offset, ptr_size); 121 | } 122 | memcpy(traverse + node_next_offset, &add, ptr_size); 123 | } 124 | 125 | /** 126 | * Rehashes all the keys in the unordered set. Used when storing references and 127 | * changing the keys. This should rarely be used. 128 | * 129 | * @param me the unordered set to rehash 130 | * 131 | * @return BK_OK if no error 132 | * @return -BK_ENOMEM if out of memory 133 | */ 134 | bk_err unordered_set_rehash(unordered_set me) 135 | { 136 | size_t i; 137 | char **old_buckets = me->buckets; 138 | me->buckets = calloc(me->capacity, ptr_size); 139 | if (!me->buckets) { 140 | me->buckets = old_buckets; 141 | return -BK_ENOMEM; 142 | } 143 | for (i = 0; i < me->capacity; i++) { 144 | char *traverse = old_buckets[i]; 145 | while (traverse) { 146 | char *backup; 147 | unsigned long hash; 148 | memcpy(&backup, traverse + node_next_offset, ptr_size); 149 | hash = unordered_set_hash(me, traverse + node_key_offset); 150 | memcpy(traverse + node_hash_offset, &hash, hash_size); 151 | unordered_set_add_item(me, traverse); 152 | traverse = backup; 153 | } 154 | } 155 | free(old_buckets); 156 | return BK_OK; 157 | } 158 | 159 | /** 160 | * Gets the size of the unordered set. 161 | * 162 | * @param me the unordered set to check 163 | * 164 | * @return the size of the unordered set 165 | */ 166 | size_t unordered_set_size(unordered_set me) 167 | { 168 | return me->size; 169 | } 170 | 171 | /** 172 | * Determines whether or not the unordered set is empty. 173 | * 174 | * @param me the unordered set to check 175 | * 176 | * @return BK_TRUE if the unordered set is empty, otherwise BK_FALSE 177 | */ 178 | bk_bool unordered_set_is_empty(unordered_set me) 179 | { 180 | return unordered_set_size(me) == 0; 181 | } 182 | 183 | /* 184 | * Increases the size of the set and redistributes the nodes. 185 | */ 186 | static bk_err unordered_set_resize(unordered_set me) 187 | { 188 | size_t i; 189 | const size_t old_capacity = me->capacity; 190 | const size_t new_capacity = me->capacity * BKTHOMPS_U_SET_RESIZE_RATIO; 191 | char **old_buckets = me->buckets; 192 | me->buckets = calloc(new_capacity, ptr_size); 193 | if (!me->buckets) { 194 | me->buckets = old_buckets; 195 | return -BK_ENOMEM; 196 | } 197 | me->capacity = new_capacity; 198 | for (i = 0; i < old_capacity; i++) { 199 | char *traverse = old_buckets[i]; 200 | while (traverse) { 201 | char *backup; 202 | memcpy(&backup, traverse + node_next_offset, ptr_size); 203 | unordered_set_add_item(me, traverse); 204 | traverse = backup; 205 | } 206 | } 207 | free(old_buckets); 208 | return BK_OK; 209 | } 210 | 211 | /* 212 | * Determines if an element is equal to the key. 213 | */ 214 | static bk_bool unordered_set_is_equal(unordered_set me, char *const item, 215 | const unsigned long hash, 216 | const void *const key) 217 | { 218 | unsigned long item_hash; 219 | memcpy(&item_hash, item + node_hash_offset, hash_size); 220 | return item_hash == hash && 221 | me->comparator(item + node_key_offset, key) == 0; 222 | } 223 | 224 | /* 225 | * Creates an element to add. 226 | */ 227 | static char *unordered_set_create_element(unordered_set me, 228 | const unsigned long hash, 229 | const void *const key) 230 | { 231 | char *init = malloc(ptr_size + hash_size + me->key_size); 232 | if (!init) { 233 | return NULL; 234 | } 235 | memset(init + node_next_offset, 0, ptr_size); 236 | memcpy(init + node_hash_offset, &hash, hash_size); 237 | memcpy(init + node_key_offset, key, me->key_size); 238 | return init; 239 | } 240 | 241 | /** 242 | * Adds an element to the unordered set if the unordered set does not already 243 | * contain it. The pointer to the key being passed in should point to the key 244 | * type which this unordered set holds. For example, if this unordered set holds 245 | * key integers, the key pointer should be a pointer to an integer. Since the 246 | * key is being copied, the pointer only has to be valid when this function is 247 | * called. 248 | * 249 | * @param me the unordered set to add to 250 | * @param key the element to add 251 | * 252 | * @return BK_OK if no error 253 | * @return -BK_ENOMEM if out of memory 254 | */ 255 | int unordered_set_put(unordered_set me, void *const key) 256 | { 257 | const unsigned long hash = unordered_set_hash(me, key); 258 | size_t index; 259 | if (me->size + 1 >= (size_t) (BKTHOMPS_U_SET_RESIZE_AT * me->capacity)) { 260 | const bk_err rc = unordered_set_resize(me); 261 | if (rc != BK_OK) { 262 | return rc; 263 | } 264 | } 265 | index = hash % me->capacity; 266 | if (!me->buckets[index]) { 267 | me->buckets[index] = unordered_set_create_element(me, hash, key); 268 | if (!me->buckets[index]) { 269 | return -BK_ENOMEM; 270 | } 271 | } else { 272 | char *traverse = me->buckets[index]; 273 | char *traverse_next; 274 | if (unordered_set_is_equal(me, traverse, hash, key)) { 275 | return BK_OK; 276 | } 277 | memcpy(&traverse_next, traverse + node_next_offset, ptr_size); 278 | while (traverse_next) { 279 | traverse = traverse_next; 280 | memcpy(&traverse_next, traverse + node_next_offset, ptr_size); 281 | if (unordered_set_is_equal(me, traverse, hash, key)) { 282 | return BK_OK; 283 | } 284 | } 285 | traverse_next = unordered_set_create_element(me, hash, key); 286 | if (!traverse_next) { 287 | return -BK_ENOMEM; 288 | } 289 | memcpy(traverse + node_next_offset, &traverse_next, ptr_size); 290 | } 291 | me->size++; 292 | return BK_OK; 293 | } 294 | 295 | /** 296 | * Determines if the unordered set contains the specified element. The pointer 297 | * to the key being passed in should point to the key type which this unordered 298 | * set holds. For example, if this unordered set holds key integers, the key 299 | * pointer should be a pointer to an integer. Since the key is being copied, 300 | * the pointer only has to be valid when this function is called. 301 | * 302 | * @param me the unordered set to check for the element 303 | * @param key the element to check 304 | * 305 | * @return BK_TRUE if the unordered set contained the element, 306 | * otherwise BK_FALSE 307 | */ 308 | int unordered_set_contains(unordered_set me, void *const key) 309 | { 310 | const unsigned long hash = unordered_set_hash(me, key); 311 | char *traverse = me->buckets[hash % me->capacity]; 312 | while (traverse) { 313 | if (unordered_set_is_equal(me, traverse, hash, key)) { 314 | return BK_TRUE; 315 | } 316 | memcpy(&traverse, traverse + node_next_offset, ptr_size); 317 | } 318 | return BK_FALSE; 319 | } 320 | 321 | /** 322 | * Removes the key from the unordered set if it contains it. The pointer to the 323 | * key being passed in should point to the key type which this unordered set 324 | * holds. For example, if this unordered set holds key integers, the key pointer 325 | * should be a pointer to an integer. Since the key is being copied, the pointer 326 | * only has to be valid when this function is called. 327 | * 328 | * @param me the unordered set to remove a key from 329 | * @param key the key to remove 330 | * 331 | * @return BK_TRUE if the unordered set contained the key, otherwise BK_FALSE 332 | */ 333 | int unordered_set_remove(unordered_set me, void *const key) 334 | { 335 | char *traverse; 336 | char *traverse_next; 337 | const unsigned long hash = unordered_set_hash(me, key); 338 | const size_t index = hash % me->capacity; 339 | if (!me->buckets[index]) { 340 | return BK_FALSE; 341 | } 342 | traverse = me->buckets[index]; 343 | if (unordered_set_is_equal(me, traverse, hash, key)) { 344 | memcpy(me->buckets + index, traverse + node_next_offset, ptr_size); 345 | free(traverse); 346 | me->size--; 347 | return BK_TRUE; 348 | } 349 | memcpy(&traverse_next, traverse + node_next_offset, ptr_size); 350 | while (traverse_next) { 351 | if (unordered_set_is_equal(me, traverse_next, hash, key)) { 352 | memcpy(traverse + node_next_offset, 353 | traverse_next + node_next_offset, ptr_size); 354 | free(traverse_next); 355 | me->size--; 356 | return BK_TRUE; 357 | } 358 | traverse = traverse_next; 359 | memcpy(&traverse_next, traverse + node_next_offset, ptr_size); 360 | } 361 | return BK_FALSE; 362 | } 363 | 364 | /** 365 | * Clears the keys from the unordered set. 366 | * 367 | * @param me the unordered set to clear 368 | * 369 | * @return BK_OK if no error 370 | * @return -BK_ENOMEM if out of memory 371 | */ 372 | int unordered_set_clear(unordered_set me) 373 | { 374 | size_t i; 375 | char **updated_buckets = calloc(BKTHOMPS_U_SET_STARTING_BUCKETS, ptr_size); 376 | if (!updated_buckets) { 377 | return -BK_ENOMEM; 378 | } 379 | for (i = 0; i < me->capacity; i++) { 380 | char *traverse = me->buckets[i]; 381 | while (traverse) { 382 | char *backup = traverse; 383 | memcpy(&traverse, traverse + node_next_offset, ptr_size); 384 | free(backup); 385 | } 386 | } 387 | free(me->buckets); 388 | me->size = 0; 389 | me->capacity = BKTHOMPS_U_SET_STARTING_BUCKETS; 390 | me->buckets = updated_buckets; 391 | return BK_OK; 392 | } 393 | 394 | /** 395 | * Frees the unordered set memory. Performing further operations after calling 396 | * this function results in undefined behavior. Freeing NULL is legal, and 397 | * causes no operation to be performed. 398 | * 399 | * @param me the unordered set to free from memory 400 | * 401 | * @return NULL 402 | */ 403 | unordered_set unordered_set_destroy(unordered_set me) 404 | { 405 | if (me) { 406 | unordered_set_clear(me); 407 | free(me->buckets); 408 | free(me); 409 | } 410 | return NULL; 411 | } 412 | -------------------------------------------------------------------------------- /tst/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "test.h" 3 | 4 | #if STUB_MALLOC 5 | 6 | #define _GNU_SOURCE 7 | #include 8 | 9 | #ifndef RTLD_NEXT 10 | #define RTLD_NEXT ((void *) -1L) 11 | #endif 12 | 13 | int fail_malloc = 0; 14 | int fail_calloc = 0; 15 | int fail_realloc = 0; 16 | 17 | int delay_fail_malloc = 0; 18 | int delay_fail_calloc = 0; 19 | int delay_fail_realloc = 0; 20 | 21 | static void *(*real_malloc)(size_t); 22 | static void *(*real_calloc)(size_t, size_t); 23 | static void *(*real_realloc)(void *, size_t); 24 | 25 | void *malloc(size_t size) 26 | { 27 | if (!real_malloc) { 28 | *(void **) (&real_malloc) = dlsym(RTLD_NEXT, "malloc"); 29 | } 30 | if (delay_fail_malloc == 0 && fail_malloc == 1) { 31 | fail_malloc = 0; 32 | return NULL; 33 | } 34 | if (delay_fail_malloc > 0) { 35 | delay_fail_malloc--; 36 | } 37 | return real_malloc(size); 38 | } 39 | 40 | void *calloc(size_t count, size_t size) 41 | { 42 | if (!real_calloc) { 43 | *(void **) (&real_calloc) = dlsym(RTLD_NEXT, "calloc"); 44 | } 45 | if (delay_fail_calloc == 0 && fail_calloc == 1) { 46 | fail_calloc = 0; 47 | return NULL; 48 | } 49 | if (delay_fail_calloc > 0) { 50 | delay_fail_calloc--; 51 | } 52 | return real_calloc(count, size); 53 | } 54 | 55 | void *realloc(void *ptr, size_t new_size) 56 | { 57 | if (!real_realloc) { 58 | *(void **) (&real_realloc) = dlsym(RTLD_NEXT, "realloc"); 59 | } 60 | if (delay_fail_realloc == 0 && fail_realloc == 1) { 61 | fail_realloc = 0; 62 | return NULL; 63 | } 64 | if (delay_fail_realloc > 0) { 65 | delay_fail_realloc--; 66 | } 67 | return real_realloc(ptr, new_size); 68 | } 69 | 70 | #endif /* STUB_MALLOC */ 71 | 72 | int main(void) 73 | { 74 | test_array(); 75 | test_vector(); 76 | test_deque(); 77 | test_forward_list(); 78 | test_list(); 79 | test_set(); 80 | test_map(); 81 | test_multiset(); 82 | test_multimap(); 83 | test_unordered_set(); 84 | test_unordered_map(); 85 | test_unordered_multiset(); 86 | test_unordered_multimap(); 87 | test_stack(); 88 | test_queue(); 89 | test_priority_queue(); 90 | printf("Tests Passed\n"); 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /tst/test.h: -------------------------------------------------------------------------------- 1 | #ifndef CONTAINERS_TEST_H 2 | #define CONTAINERS_TEST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define STUB_MALLOC 1 11 | 12 | #if STUB_MALLOC 13 | 14 | extern int fail_malloc; 15 | extern int fail_calloc; 16 | extern int fail_realloc; 17 | 18 | extern int delay_fail_malloc; 19 | extern int delay_fail_calloc; 20 | extern int delay_fail_realloc; 21 | 22 | #endif /* STUB_MALLOC */ 23 | 24 | void test_array(void); 25 | void test_vector(void); 26 | void test_deque(void); 27 | void test_forward_list(void); 28 | void test_list(void); 29 | void test_set(void); 30 | void test_map(void); 31 | void test_multiset(void); 32 | void test_multimap(void); 33 | void test_unordered_set(void); 34 | void test_unordered_map(void); 35 | void test_unordered_multiset(void); 36 | void test_unordered_multimap(void); 37 | void test_stack(void); 38 | void test_queue(void); 39 | void test_priority_queue(void); 40 | 41 | #endif /* CONTAINERS_TEST_H */ 42 | -------------------------------------------------------------------------------- /tst/test_array.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/array.h" 3 | 4 | static void test_invalid_init(void) 5 | { 6 | const size_t max_size = -1; 7 | assert(!array_init(1, 0)); 8 | assert(!array_init(max_size, max_size)); 9 | assert(!array_init(1, max_size)); 10 | } 11 | 12 | static void test_empty_array(void) 13 | { 14 | int get = 0xfacade; 15 | int arr[2] = {0xfacade, 0xfacade}; 16 | array me = array_init(0, sizeof(int)); 17 | assert(me); 18 | assert(array_size(me) == 0); 19 | array_copy_to_array(arr, me); 20 | assert(arr[0] == 0xfacade); 21 | assert(arr[1] == 0xfacade); 22 | assert(!array_get_data(me)); 23 | assert(array_set(me, 0, &get) == -EINVAL); 24 | assert(array_get(&get, me, 0) == -EINVAL); 25 | assert(!array_destroy(me)); 26 | } 27 | 28 | static void test_individual_operations(array me) 29 | { 30 | int i; 31 | for (i = 0; i < 10; i++) { 32 | int get = 0xfacade; 33 | array_get(&get, me, i); 34 | assert(get == 0); 35 | } 36 | for (i = 0; i < 10; i++) { 37 | int get = 0xfacade; 38 | array_set(me, i, &i); 39 | array_get(&get, me, i); 40 | assert(get == i); 41 | } 42 | for (i = 0; i < 10; i++) { 43 | int get = 0xfacade; 44 | array_get(&get, me, i); 45 | assert(get == i); 46 | } 47 | } 48 | 49 | static void test_array_copying(array me) 50 | { 51 | int i; 52 | int *data; 53 | int arr[10] = {0}; 54 | array_copy_to_array(arr, me); 55 | for (i = 0; i < 10; i++) { 56 | assert(arr[i] == i); 57 | } 58 | data = array_get_data(me); 59 | for (i = 0; i < 10; i++) { 60 | assert(data[i] == i); 61 | } 62 | } 63 | 64 | static void test_out_of_bounds(array me) 65 | { 66 | int get = 0xfacade; 67 | assert(array_set(me, -1, &get) == -EINVAL); 68 | assert(array_get(&get, me, -1) == -EINVAL); 69 | } 70 | 71 | static void test_not_empty_array(void) 72 | { 73 | array me = array_init(10, sizeof(int)); 74 | assert(me); 75 | assert(array_size(me) == 10); 76 | test_individual_operations(me); 77 | test_array_copying(me); 78 | test_out_of_bounds(me); 79 | me = array_destroy(me); 80 | assert(!me); 81 | } 82 | 83 | #if STUB_MALLOC 84 | static void test_init_out_of_memory(void) 85 | { 86 | fail_malloc = 1; 87 | assert(!array_init(10, sizeof(int))); 88 | } 89 | #endif 90 | 91 | struct big_object { 92 | int n; 93 | double d; 94 | signed char c[8]; 95 | }; 96 | 97 | static void test_big_object(void) 98 | { 99 | int i; 100 | array me = array_init(16, sizeof(struct big_object)); 101 | assert(me); 102 | for (i = 0; i < 16; i++) { 103 | int j; 104 | struct big_object b; 105 | b.n = INT_MIN + i; 106 | b.d = i + 0.5; 107 | for (j = 0; j < 8; j++) { 108 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 109 | } 110 | assert(array_set(me, i, &b) == 0); 111 | b.n = -1; 112 | b.d = -1; 113 | for (j = 0; j < 8; j++) { 114 | b.c[j] = -1; 115 | } 116 | } 117 | for (i = 0; i < 16; i++) { 118 | int j; 119 | struct big_object b; 120 | assert(array_get(&b, me, i) == 0); 121 | assert(b.n == INT_MIN + i); 122 | assert(b.d == i + 0.5); 123 | for (j = 0; j < 8; j++) { 124 | assert(b.c[j] == SCHAR_MIN + i + j); 125 | } 126 | } 127 | assert(!array_destroy(me)); 128 | } 129 | 130 | static void test_add_all(void) 131 | { 132 | int get; 133 | size_t i; 134 | int arr_1[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 135 | int arr_2[] = {100, 200, 300, 400, 500, 600, 700, 800, 900}; 136 | array me = array_init(10, sizeof(int)); 137 | assert(array_add_all(me, arr_1, 11) == -BK_EINVAL); 138 | assert(array_add_all(me, arr_1, 10) == BK_OK); 139 | for (i = 0; i < sizeof(arr_1) / sizeof(*arr_1); i++) { 140 | array_get(&get, me, i); 141 | assert(get == arr_1[i]); 142 | } 143 | assert(array_add_all(me, arr_2, 9) == BK_OK); 144 | for (i = 0; i < sizeof(arr_2) / sizeof(*arr_2); i++) { 145 | array_get(&get, me, i); 146 | assert(get == arr_2[i]); 147 | } 148 | array_get(&get, me, 9); 149 | assert(get == 10); 150 | array_destroy(me); 151 | } 152 | 153 | void test_array(void) 154 | { 155 | test_invalid_init(); 156 | test_empty_array(); 157 | test_not_empty_array(); 158 | #if STUB_MALLOC 159 | test_init_out_of_memory(); 160 | #endif 161 | test_big_object(); 162 | test_add_all(); 163 | array_destroy(NULL); 164 | } 165 | -------------------------------------------------------------------------------- /tst/test_forward_list.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/forward_list.h" 3 | 4 | static void test_invalid_init(void) 5 | { 6 | const size_t max_size = -1; 7 | assert(!forward_list_init(0)); 8 | assert(!forward_list_init(max_size)); 9 | } 10 | 11 | static void test_front(forward_list me) 12 | { 13 | int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 14 | int get_arr[10] = {0}; 15 | int get; 16 | size_t i; 17 | assert(forward_list_size(me) == 0); 18 | assert(forward_list_is_empty(me)); 19 | for (i = 0; i < 10; i++) { 20 | forward_list_add_first(me, &val[i]); 21 | assert(forward_list_size(me) == i + 1); 22 | get = 0; 23 | forward_list_get_first(&get, me); 24 | assert(get == val[i]); 25 | } 26 | assert(forward_list_size(me) == 10); 27 | assert(!forward_list_is_empty(me)); 28 | forward_list_copy_to_array(get_arr, me); 29 | for (i = 0; i < 10; i++) { 30 | get = 0; 31 | forward_list_get_at(&get, me, i); 32 | assert(get == val[9 - i]); 33 | assert(get_arr[i] == val[9 - i]); 34 | } 35 | for (i = 0; i < 7; i++) { 36 | forward_list_remove_last(me); 37 | } 38 | } 39 | 40 | static void test_linear_operations(forward_list me) 41 | { 42 | int trimmed[5] = {0}; 43 | int index; 44 | int first; 45 | int add; 46 | int get; 47 | int set; 48 | int i; 49 | forward_list_copy_to_array(trimmed, me); 50 | assert(forward_list_size(me) == 3); 51 | for (i = 0; i < 3; i++) { 52 | assert(10 - i == trimmed[i]); 53 | } 54 | index = forward_list_size(me); 55 | add = 3; 56 | forward_list_add_at(me, index, &add); 57 | add = -1; 58 | forward_list_add_at(me, 1, &add); 59 | add = -2; 60 | forward_list_add_last(me, &add); 61 | assert(forward_list_size(me) == 6); 62 | get = 0xfacade; 63 | forward_list_get_first(&get, me); 64 | assert(get == 10); 65 | get = 0xfacade; 66 | forward_list_get_at(&get, me, 0); 67 | assert(get == 10); 68 | forward_list_get_at(&get, me, 1); 69 | assert(get == -1); 70 | forward_list_get_at(&get, me, 2); 71 | assert(get == 9); 72 | forward_list_get_at(&get, me, 3); 73 | assert(get == 8); 74 | forward_list_get_at(&get, me, 4); 75 | assert(get == 3); 76 | forward_list_get_at(&get, me, 5); 77 | assert(get == -2); 78 | get = 0xfacade; 79 | forward_list_get_last(&get, me); 80 | assert(get == -2); 81 | forward_list_remove_first(me); 82 | forward_list_remove_at(me, 2); 83 | forward_list_remove_last(me); 84 | get = 34; 85 | forward_list_add_at(me, 0, &get); 86 | first = 0xfacade; 87 | forward_list_get_first(&first, me); 88 | assert(first == get); 89 | forward_list_remove_first(me); 90 | assert(forward_list_size(me) == 3); 91 | get = 345; 92 | forward_list_get_first(&get, me); 93 | assert(get == -1); 94 | forward_list_get_at(&get, me, 1); 95 | assert(get == 9); 96 | forward_list_get_last(&get, me); 97 | assert(get == 3); 98 | set = 12; 99 | forward_list_set_first(me, &set); 100 | set = 13; 101 | forward_list_set_at(me, 1, &set); 102 | set = 14; 103 | forward_list_set_last(me, &set); 104 | } 105 | 106 | static void test_array_copy(forward_list me) 107 | { 108 | int arr[3] = {0}; 109 | int set; 110 | forward_list_copy_to_array(arr, me); 111 | assert(arr[0] == 12); 112 | assert(arr[1] == 13); 113 | assert(arr[2] == 14); 114 | set = -5; 115 | forward_list_set_at(me, 0, &set); 116 | set = -6; 117 | forward_list_set_at(me, 1, &set); 118 | set = -7; 119 | forward_list_set_at(me, 2, &set); 120 | forward_list_copy_to_array(arr, me); 121 | assert(arr[0] == -5); 122 | assert(arr[1] == -6); 123 | assert(arr[2] == -7); 124 | } 125 | 126 | static void test_invalid_index(forward_list me) 127 | { 128 | int set = 0xfacade; 129 | assert(forward_list_set_at(me, 4, &set) == -EINVAL); 130 | assert(forward_list_get_at(&set, me, 4) == -EINVAL); 131 | assert(forward_list_remove_at(me, 4) == -EINVAL); 132 | assert(forward_list_add_at(me, 5, &set) == -EINVAL); 133 | assert(forward_list_set_at(me, -1, &set) == -EINVAL); 134 | assert(forward_list_get_at(&set, me, -1) == -EINVAL); 135 | assert(forward_list_remove_at(me, -1) == -EINVAL); 136 | assert(forward_list_add_at(me, -1, &set) == -EINVAL); 137 | forward_list_clear(me); 138 | assert(forward_list_size(me) == 0); 139 | assert(forward_list_is_empty(me)); 140 | assert(forward_list_remove_first(me) == -EINVAL); 141 | assert(forward_list_remove_last(me) == -EINVAL); 142 | } 143 | 144 | static void test_basic(void) 145 | { 146 | forward_list me = forward_list_init(sizeof(int)); 147 | assert(me); 148 | test_front(me); 149 | test_linear_operations(me); 150 | test_array_copy(me); 151 | test_invalid_index(me); 152 | assert(!forward_list_destroy(me)); 153 | } 154 | 155 | static void test_add_back(void) 156 | { 157 | int i; 158 | forward_list me = forward_list_init(sizeof(int)); 159 | assert(me); 160 | for (i = 1; i < 10000; i++) { 161 | int get = 0xfacade; 162 | forward_list_add_last(me, &i); 163 | forward_list_get_last(&get, me); 164 | assert(get == i); 165 | if (i % 5 == 0) { 166 | forward_list_remove_last(me); 167 | forward_list_get_last(&get, me); 168 | assert(get == i - 1); 169 | } 170 | } 171 | assert(!forward_list_destroy(me)); 172 | } 173 | 174 | #if STUB_MALLOC 175 | static void test_init_out_of_memory(void) 176 | { 177 | fail_malloc = 1; 178 | assert(!forward_list_init(sizeof(int))); 179 | } 180 | #endif 181 | 182 | #if STUB_MALLOC 183 | static void test_add_first_out_of_memory(void) 184 | { 185 | int i; 186 | forward_list me = forward_list_init(sizeof(int)); 187 | assert(me); 188 | for (i = 0; i < 16; i++) { 189 | assert(forward_list_add_first(me, &i) == 0); 190 | } 191 | assert(forward_list_size(me) == 16); 192 | fail_malloc = 1; 193 | assert(forward_list_add_first(me, &i) == -ENOMEM); 194 | assert(forward_list_size(me) == 16); 195 | for (i = 0; i < 16; i++) { 196 | int get = 0xfacade; 197 | assert(forward_list_get_at(&get, me, i) == 0); 198 | assert(get == 15 - i); 199 | } 200 | assert(!forward_list_destroy(me)); 201 | } 202 | #endif 203 | 204 | #if STUB_MALLOC 205 | static void test_add_at_out_of_memory(void) 206 | { 207 | int get; 208 | int i; 209 | forward_list me = forward_list_init(sizeof(int)); 210 | assert(me); 211 | i = 982; 212 | assert(forward_list_add_first(me, &i) == 0); 213 | i = 157; 214 | assert(forward_list_add_first(me, &i) == 0); 215 | for (i = 1; i < 15; i++) { 216 | assert(forward_list_add_at(me, i, &i) == 0); 217 | } 218 | assert(forward_list_size(me) == 16); 219 | fail_malloc = 1; 220 | assert(forward_list_add_at(me, 5, &i) == -ENOMEM); 221 | assert(forward_list_size(me) == 16); 222 | get = 0xfacade; 223 | assert(forward_list_get_at(&get, me, 0) == 0); 224 | assert(get == 157); 225 | for (i = 1; i < 15; i++) { 226 | get = 0xfacade; 227 | assert(forward_list_get_at(&get, me, i) == 0); 228 | assert(get == i); 229 | } 230 | assert(forward_list_size(me) == 16); 231 | get = 0xfacade; 232 | assert(forward_list_get_at(&get, me, 0) == 0); 233 | assert(get == 157); 234 | for (i = 1; i < 15; i++) { 235 | get = 0xfacade; 236 | assert(forward_list_get_at(&get, me, i) == 0); 237 | assert(get == i); 238 | } 239 | get = 0xfacade; 240 | assert(forward_list_get_at(&get, me, 15) == 0); 241 | assert(get == 982); 242 | assert(!forward_list_destroy(me)); 243 | } 244 | #endif 245 | 246 | #if STUB_MALLOC 247 | static void test_add_last_out_of_memory(void) 248 | { 249 | int i; 250 | forward_list me = forward_list_init(sizeof(int)); 251 | assert(me); 252 | for (i = 0; i < 16; i++) { 253 | assert(forward_list_add_last(me, &i) == 0); 254 | } 255 | assert(forward_list_size(me) == 16); 256 | fail_malloc = 1; 257 | assert(forward_list_add_last(me, &i) == -ENOMEM); 258 | assert(forward_list_size(me) == 16); 259 | for (i = 0; i < 16; i++) { 260 | int get = 0xfacade; 261 | assert(forward_list_get_at(&get, me, i) == 0); 262 | assert(get == i); 263 | } 264 | assert(!forward_list_destroy(me)); 265 | } 266 | #endif 267 | 268 | struct pair { 269 | int cur_node; 270 | int cur_cost; 271 | }; 272 | 273 | static int test_puzzle_forwards(int start_node, int dest_node) 274 | { 275 | forward_list q = forward_list_init(sizeof(struct pair)); 276 | struct pair cur; 277 | cur.cur_node = start_node; 278 | cur.cur_cost = 0; 279 | assert(forward_list_is_empty(q)); 280 | forward_list_add_last(q, &cur); 281 | assert(forward_list_size(q) == 1); 282 | while (!forward_list_is_empty(q)) { 283 | int node; 284 | int cost; 285 | forward_list_get_first(&cur, q); 286 | forward_list_remove_first(q); 287 | node = cur.cur_node; 288 | cost = cur.cur_cost; 289 | if (node > 2 * dest_node || node < 1) { 290 | continue; 291 | } 292 | if (node == dest_node) { 293 | forward_list_destroy(q); 294 | return cost; 295 | } 296 | cur.cur_cost = cost + 1; 297 | cur.cur_node = node - 1; 298 | forward_list_add_last(q, &cur); 299 | assert(cur.cur_cost == cost + 1); 300 | assert(cur.cur_node == node - 1); 301 | cur.cur_node = 2 * node; 302 | forward_list_add_last(q, &cur); 303 | assert(cur.cur_cost == cost + 1); 304 | assert(cur.cur_node == 2 * node); 305 | } 306 | forward_list_destroy(q); 307 | return -1; 308 | } 309 | 310 | static int test_puzzle_backwards(int start_node, int dest_node) 311 | { 312 | forward_list q = forward_list_init(sizeof(struct pair)); 313 | struct pair cur; 314 | cur.cur_node = start_node; 315 | cur.cur_cost = 0; 316 | assert(forward_list_is_empty(q)); 317 | forward_list_add_first(q, &cur); 318 | assert(forward_list_size(q) == 1); 319 | while (!forward_list_is_empty(q)) { 320 | int node; 321 | int cost; 322 | forward_list_get_last(&cur, q); 323 | forward_list_remove_last(q); 324 | node = cur.cur_node; 325 | cost = cur.cur_cost; 326 | if (node > 2 * dest_node || node < 1) { 327 | continue; 328 | } 329 | if (node == dest_node) { 330 | forward_list_destroy(q); 331 | return cost; 332 | } 333 | cur.cur_cost = cost + 1; 334 | cur.cur_node = node - 1; 335 | forward_list_add_first(q, &cur); 336 | assert(cur.cur_cost == cost + 1); 337 | assert(cur.cur_node == node - 1); 338 | cur.cur_node = 2 * node; 339 | forward_list_add_first(q, &cur); 340 | assert(cur.cur_cost == cost + 1); 341 | assert(cur.cur_node == 2 * node); 342 | } 343 | forward_list_destroy(q); 344 | return -1; 345 | } 346 | 347 | struct big_object { 348 | int n; 349 | double d; 350 | signed char c[8]; 351 | }; 352 | 353 | static void test_big_object(void) 354 | { 355 | int i; 356 | forward_list me = forward_list_init(sizeof(struct big_object)); 357 | assert(me); 358 | for (i = 0; i < 16; i++) { 359 | int j; 360 | struct big_object b; 361 | b.n = INT_MIN + i; 362 | b.d = i + 0.5; 363 | for (j = 0; j < 8; j++) { 364 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 365 | } 366 | assert(forward_list_add_first(me, &b) == 0); 367 | b.n = -1; 368 | b.d = -1; 369 | for (j = 0; j < 8; j++) { 370 | b.c[j] = -1; 371 | } 372 | } 373 | for (i = 0; i < 16; i++) { 374 | int j; 375 | struct big_object b; 376 | assert(forward_list_get_last(&b, me) == 0); 377 | assert(forward_list_remove_last(me) == 0); 378 | assert(b.n == INT_MIN + i); 379 | assert(b.d == i + 0.5); 380 | for (j = 0; j < 8; j++) { 381 | assert(b.c[j] == SCHAR_MIN + i + j); 382 | } 383 | } 384 | assert(!forward_list_destroy(me)); 385 | } 386 | 387 | static void test_add_all(void) 388 | { 389 | const size_t max_size = -1; 390 | size_t i; 391 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 392 | forward_list me = forward_list_init(sizeof(int)); 393 | assert(forward_list_add_all(me, arr, 0) == BK_OK); 394 | assert(forward_list_size(me) == 0); 395 | assert(forward_list_add_all(me, arr, 10) == BK_OK); 396 | assert(forward_list_size(me) == 10); 397 | for (i = 0; i < 10; i++) { 398 | int get; 399 | assert(forward_list_get_at(&get, me, i) == BK_OK); 400 | assert(get == (int) i + 1); 401 | } 402 | assert(forward_list_add_all(me, arr, 10) == BK_OK); 403 | assert(forward_list_size(me) == 20); 404 | assert(forward_list_remove_last(me) == BK_OK); 405 | assert(forward_list_add_all(me, arr, 10) == BK_OK); 406 | assert(forward_list_size(me) == 29); 407 | for (i = 0; i < 29; i++) { 408 | int get; 409 | int n = i; 410 | if (i >= 19) { 411 | n++; 412 | } 413 | assert(forward_list_get_at(&get, me, i) == BK_OK); 414 | assert(get == n % 10 + 1); 415 | } 416 | assert(forward_list_add_all(me, arr, max_size) == -BK_ERANGE); 417 | assert(forward_list_size(me) == 29); 418 | #if STUB_MALLOC 419 | fail_malloc = 1; 420 | assert(forward_list_add_all(me, arr, 10) == -BK_ENOMEM); 421 | assert(forward_list_size(me) == 29); 422 | fail_malloc = 1; 423 | delay_fail_malloc = 5; 424 | assert(forward_list_add_all(me, arr, 10) == -BK_ENOMEM); 425 | assert(forward_list_size(me) == 29); 426 | #endif 427 | forward_list_destroy(me); 428 | } 429 | 430 | void test_forward_list(void) 431 | { 432 | test_invalid_init(); 433 | test_basic(); 434 | test_add_back(); 435 | #if STUB_MALLOC 436 | test_init_out_of_memory(); 437 | test_add_first_out_of_memory(); 438 | test_add_at_out_of_memory(); 439 | test_add_last_out_of_memory(); 440 | #endif 441 | assert(test_puzzle_forwards(2, 5) == 4); 442 | assert(test_puzzle_forwards(2, 10) == 5); 443 | assert(test_puzzle_backwards(2, 5) == 4); 444 | assert(test_puzzle_backwards(2, 10) == 5); 445 | test_big_object(); 446 | test_add_all(); 447 | forward_list_destroy(NULL); 448 | } 449 | -------------------------------------------------------------------------------- /tst/test_list.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/list.h" 3 | 4 | static void test_invalid_init(void) 5 | { 6 | const size_t max_size = -1; 7 | assert(!list_init(0)); 8 | assert(!list_init(max_size)); 9 | } 10 | 11 | static void test_front(list me) 12 | { 13 | int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 14 | int get_arr[10] = {0}; 15 | int get; 16 | size_t i; 17 | assert(list_size(me) == 0); 18 | assert(list_is_empty(me)); 19 | for (i = 0; i < 10; i++) { 20 | list_add_first(me, &val[i]); 21 | assert(list_size(me) == i + 1); 22 | get = 0; 23 | list_get_first(&get, me); 24 | assert(get == val[i]); 25 | } 26 | assert(list_size(me) == 10); 27 | assert(!list_is_empty(me)); 28 | list_copy_to_array(get_arr, me); 29 | for (i = 0; i < 10; i++) { 30 | get = 0; 31 | list_get_at(&get, me, i); 32 | assert(get == val[9 - i]); 33 | assert(get_arr[i] == val[9 - i]); 34 | } 35 | for (i = 0; i < 7; i++) { 36 | list_remove_last(me); 37 | } 38 | } 39 | 40 | static void test_linear_operations(list me) 41 | { 42 | int trimmed[5] = {0}; 43 | int index; 44 | int first; 45 | int add; 46 | int get; 47 | int set; 48 | int i; 49 | list_copy_to_array(trimmed, me); 50 | assert(list_size(me) == 3); 51 | for (i = 0; i < 3; i++) { 52 | assert(10 - i == trimmed[i]); 53 | } 54 | index = list_size(me); 55 | add = 3; 56 | list_add_at(me, index, &add); 57 | add = -1; 58 | list_add_at(me, 1, &add); 59 | add = -2; 60 | list_add_last(me, &add); 61 | assert(list_size(me) == 6); 62 | get = 0xfacade; 63 | list_get_first(&get, me); 64 | assert(get == 10); 65 | get = 0xfacade; 66 | list_get_at(&get, me, 0); 67 | assert(get == 10); 68 | list_get_at(&get, me, 1); 69 | assert(get == -1); 70 | list_get_at(&get, me, 2); 71 | assert(get == 9); 72 | list_get_at(&get, me, 3); 73 | assert(get == 8); 74 | list_get_at(&get, me, 4); 75 | assert(get == 3); 76 | list_get_at(&get, me, 5); 77 | assert(get == -2); 78 | get = 0xfacade; 79 | list_get_last(&get, me); 80 | assert(get == -2); 81 | list_remove_first(me); 82 | list_remove_at(me, 2); 83 | list_remove_last(me); 84 | get = 34; 85 | list_add_at(me, 0, &get); 86 | first = 0xfacade; 87 | list_get_first(&first, me); 88 | assert(first == get); 89 | list_remove_first(me); 90 | assert(list_size(me) == 3); 91 | get = 345; 92 | list_get_first(&get, me); 93 | assert(get == -1); 94 | list_get_at(&get, me, 1); 95 | assert(get == 9); 96 | list_get_last(&get, me); 97 | assert(get == 3); 98 | set = 12; 99 | list_set_first(me, &set); 100 | set = 13; 101 | list_set_at(me, 1, &set); 102 | set = 14; 103 | list_set_last(me, &set); 104 | } 105 | 106 | static void test_array_copy(list me) 107 | { 108 | int arr[3] = {0}; 109 | int set; 110 | list_copy_to_array(arr, me); 111 | assert(arr[0] == 12); 112 | assert(arr[1] == 13); 113 | assert(arr[2] == 14); 114 | set = -5; 115 | list_set_at(me, 0, &set); 116 | set = -6; 117 | list_set_at(me, 1, &set); 118 | set = -7; 119 | list_set_at(me, 2, &set); 120 | list_copy_to_array(arr, me); 121 | assert(arr[0] == -5); 122 | assert(arr[1] == -6); 123 | assert(arr[2] == -7); 124 | } 125 | 126 | static void test_invalid_index(list me) 127 | { 128 | int set = 0xfacade; 129 | assert(list_set_at(me, 4, &set) == -EINVAL); 130 | assert(list_get_at(&set, me, 4) == -EINVAL); 131 | assert(list_remove_at(me, 4) == -EINVAL); 132 | assert(list_add_at(me, 5, &set) == -EINVAL); 133 | assert(list_set_at(me, -1, &set) == -EINVAL); 134 | assert(list_get_at(&set, me, -1) == -EINVAL); 135 | assert(list_remove_at(me, -1) == -EINVAL); 136 | assert(list_add_at(me, -1, &set) == -EINVAL); 137 | list_clear(me); 138 | assert(list_size(me) == 0); 139 | assert(list_is_empty(me)); 140 | assert(list_remove_first(me) == -EINVAL); 141 | assert(list_remove_last(me) == -EINVAL); 142 | } 143 | 144 | static void test_basic(void) 145 | { 146 | list me = list_init(sizeof(int)); 147 | assert(me); 148 | test_front(me); 149 | test_linear_operations(me); 150 | test_array_copy(me); 151 | test_invalid_index(me); 152 | assert(!list_destroy(me)); 153 | } 154 | 155 | #if STUB_MALLOC 156 | static void test_init_out_of_memory(void) 157 | { 158 | fail_malloc = 1; 159 | assert(!list_init(sizeof(int))); 160 | } 161 | #endif 162 | 163 | #if STUB_MALLOC 164 | static void test_add_first_out_of_memory(void) 165 | { 166 | int i; 167 | list me = list_init(sizeof(int)); 168 | assert(me); 169 | for (i = 0; i < 16; i++) { 170 | assert(list_add_first(me, &i) == 0); 171 | } 172 | assert(list_size(me) == 16); 173 | fail_malloc = 1; 174 | assert(list_add_first(me, &i) == -ENOMEM); 175 | assert(list_size(me) == 16); 176 | for (i = 0; i < 16; i++) { 177 | int get = 0xfacade; 178 | assert(list_get_at(&get, me, i) == 0); 179 | assert(get == 15 - i); 180 | } 181 | assert(!list_destroy(me)); 182 | } 183 | #endif 184 | 185 | #if STUB_MALLOC 186 | static void test_add_at_out_of_memory(void) 187 | { 188 | int get; 189 | int i; 190 | list me = list_init(sizeof(int)); 191 | assert(me); 192 | i = 982; 193 | assert(list_add_first(me, &i) == 0); 194 | i = 157; 195 | assert(list_add_first(me, &i) == 0); 196 | for (i = 1; i < 15; i++) { 197 | assert(list_add_at(me, i, &i) == 0); 198 | } 199 | assert(list_size(me) == 16); 200 | fail_malloc = 1; 201 | assert(list_add_at(me, 5, &i) == -ENOMEM); 202 | assert(list_size(me) == 16); 203 | get = 0xfacade; 204 | assert(list_get_at(&get, me, 0) == 0); 205 | assert(get == 157); 206 | for (i = 1; i < 15; i++) { 207 | get = 0xfacade; 208 | assert(list_get_at(&get, me, i) == 0); 209 | assert(get == i); 210 | } 211 | get = 0xfacade; 212 | assert(list_get_at(&get, me, 15) == 0); 213 | assert(get == 982); 214 | assert(!list_destroy(me)); 215 | } 216 | #endif 217 | 218 | #if STUB_MALLOC 219 | static void test_add_last_out_of_memory(void) 220 | { 221 | int i; 222 | list me = list_init(sizeof(int)); 223 | assert(me); 224 | for (i = 0; i < 16; i++) { 225 | assert(list_add_last(me, &i) == 0); 226 | } 227 | assert(list_size(me) == 16); 228 | fail_malloc = 1; 229 | assert(list_add_last(me, &i) == -ENOMEM); 230 | assert(list_size(me) == 16); 231 | for (i = 0; i < 16; i++) { 232 | int get = 0xfacade; 233 | assert(list_get_at(&get, me, i) == 0); 234 | assert(get == i); 235 | } 236 | assert(!list_destroy(me)); 237 | } 238 | #endif 239 | 240 | void test_remove_all(void) 241 | { 242 | size_t i; 243 | list me = list_init(sizeof(int)); 244 | for (i = 0; i < 100; i++) { 245 | list_add_first(me, &i); 246 | assert(list_size(me) == i + 1); 247 | } 248 | for (i = 0; i < 100; i++) { 249 | list_remove_first(me); 250 | assert(list_size(me) == 100 - i - 1); 251 | } 252 | assert(list_is_empty(me)); 253 | for (i = 0; i < 100; i++) { 254 | list_add_first(me, &i); 255 | assert(list_size(me) == i + 1); 256 | } 257 | assert(list_size(me) == 100); 258 | assert(!list_destroy(me)); 259 | } 260 | 261 | struct pair { 262 | int cur_node; 263 | int cur_cost; 264 | }; 265 | 266 | static int test_puzzle_forwards(int start_node, int dest_node) 267 | { 268 | list q = list_init(sizeof(struct pair)); 269 | struct pair cur; 270 | cur.cur_node = start_node; 271 | cur.cur_cost = 0; 272 | assert(list_is_empty(q)); 273 | list_add_last(q, &cur); 274 | assert(list_size(q) == 1); 275 | while (!list_is_empty(q)) { 276 | int node; 277 | int cost; 278 | list_get_first(&cur, q); 279 | list_remove_first(q); 280 | node = cur.cur_node; 281 | cost = cur.cur_cost; 282 | if (node > 2 * dest_node || node < 1) { 283 | continue; 284 | } 285 | if (node == dest_node) { 286 | list_destroy(q); 287 | return cost; 288 | } 289 | cur.cur_cost = cost + 1; 290 | cur.cur_node = node - 1; 291 | list_add_last(q, &cur); 292 | assert(cur.cur_cost == cost + 1); 293 | assert(cur.cur_node == node - 1); 294 | cur.cur_node = 2 * node; 295 | list_add_last(q, &cur); 296 | assert(cur.cur_cost == cost + 1); 297 | assert(cur.cur_node == 2 * node); 298 | } 299 | list_destroy(q); 300 | return -1; 301 | } 302 | 303 | static int test_puzzle_backwards(int start_node, int dest_node) 304 | { 305 | list q = list_init(sizeof(struct pair)); 306 | struct pair cur; 307 | cur.cur_node = start_node; 308 | cur.cur_cost = 0; 309 | assert(list_is_empty(q)); 310 | list_add_first(q, &cur); 311 | assert(list_size(q) == 1); 312 | while (!list_is_empty(q)) { 313 | int node; 314 | int cost; 315 | list_get_last(&cur, q); 316 | list_remove_last(q); 317 | node = cur.cur_node; 318 | cost = cur.cur_cost; 319 | if (node > 2 * dest_node || node < 1) { 320 | continue; 321 | } 322 | if (node == dest_node) { 323 | list_destroy(q); 324 | return cost; 325 | } 326 | cur.cur_cost = cost + 1; 327 | cur.cur_node = node - 1; 328 | list_add_first(q, &cur); 329 | assert(cur.cur_cost == cost + 1); 330 | assert(cur.cur_node == node - 1); 331 | cur.cur_node = 2 * node; 332 | list_add_first(q, &cur); 333 | assert(cur.cur_cost == cost + 1); 334 | assert(cur.cur_node == 2 * node); 335 | } 336 | list_destroy(q); 337 | return -1; 338 | } 339 | 340 | struct big_object { 341 | int n; 342 | double d; 343 | signed char c[8]; 344 | }; 345 | 346 | static void test_big_object(void) 347 | { 348 | int i; 349 | list me = list_init(sizeof(struct big_object)); 350 | assert(me); 351 | for (i = 0; i < 16; i++) { 352 | int j; 353 | struct big_object b; 354 | b.n = INT_MIN + i; 355 | b.d = i + 0.5; 356 | for (j = 0; j < 8; j++) { 357 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 358 | } 359 | assert(list_add_first(me, &b) == 0); 360 | b.n = -1; 361 | b.d = -1; 362 | for (j = 0; j < 8; j++) { 363 | b.c[j] = -1; 364 | } 365 | } 366 | for (i = 0; i < 16; i++) { 367 | int j; 368 | struct big_object b; 369 | assert(list_get_last(&b, me) == 0); 370 | assert(list_remove_last(me) == 0); 371 | assert(b.n == INT_MIN + i); 372 | assert(b.d == i + 0.5); 373 | for (j = 0; j < 8; j++) { 374 | assert(b.c[j] == SCHAR_MIN + i + j); 375 | } 376 | } 377 | assert(!list_destroy(me)); 378 | } 379 | 380 | static void test_add_all(void) 381 | { 382 | const size_t max_size = -1; 383 | size_t i; 384 | int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 385 | list me = list_init(sizeof(int)); 386 | assert(list_add_all(me, arr, 0) == BK_OK); 387 | assert(list_size(me) == 0); 388 | assert(list_add_all(me, arr, 10) == BK_OK); 389 | assert(list_size(me) == 10); 390 | for (i = 0; i < 10; i++) { 391 | int get; 392 | assert(list_get_at(&get, me, i) == BK_OK); 393 | assert(get == (int) i + 1); 394 | } 395 | assert(list_add_all(me, arr, 10) == BK_OK); 396 | assert(list_size(me) == 20); 397 | assert(list_add_all(me, arr, 10) == BK_OK); 398 | assert(list_size(me) == 30); 399 | for (i = 0; i < 30; i++) { 400 | int get; 401 | assert(list_get_at(&get, me, i) == BK_OK); 402 | assert(get == (int) i % 10 + 1); 403 | } 404 | assert(list_add_all(me, arr, max_size) == -BK_ERANGE); 405 | assert(list_size(me) == 30); 406 | #if STUB_MALLOC 407 | fail_malloc = 1; 408 | assert(list_add_all(me, arr, 10) == -BK_ENOMEM); 409 | assert(list_size(me) == 30); 410 | fail_malloc = 1; 411 | delay_fail_malloc = 5; 412 | assert(list_add_all(me, arr, 10) == -BK_ENOMEM); 413 | assert(list_size(me) == 30); 414 | #endif 415 | list_destroy(me); 416 | } 417 | 418 | void test_list(void) 419 | { 420 | test_invalid_init(); 421 | test_basic(); 422 | #if STUB_MALLOC 423 | test_init_out_of_memory(); 424 | test_add_first_out_of_memory(); 425 | test_add_at_out_of_memory(); 426 | test_add_last_out_of_memory(); 427 | #endif 428 | test_remove_all(); 429 | assert(test_puzzle_forwards(2, 5) == 4); 430 | assert(test_puzzle_forwards(2, 10) == 5); 431 | assert(test_puzzle_backwards(2, 5) == 4); 432 | assert(test_puzzle_backwards(2, 10) == 5); 433 | test_big_object(); 434 | test_add_all(); 435 | list_destroy(NULL); 436 | } 437 | -------------------------------------------------------------------------------- /tst/test_priority_queue.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/vector.h" 3 | #include "../src/include/priority_queue.h" 4 | 5 | /* 6 | * Include this for the stubs. 7 | */ 8 | struct internal_priority_queue { 9 | size_t data_size; 10 | int (*comparator)(const void *const one, const void *const two); 11 | vector data; 12 | }; 13 | 14 | static void priority_queue_verify(priority_queue me) 15 | { 16 | int i; 17 | void *const vector_storage = vector_get_data(me->data); 18 | const int size = vector_size(me->data); 19 | for (i = 0; i < size; i++) { 20 | const int val = *(int *) ((char *) vector_storage + i * me->data_size); 21 | const int left_child = 2 * i + 1; 22 | const int right_child = 2 * i + 2; 23 | if (left_child < size) { 24 | void *left_data = 25 | (char *) vector_storage + left_child * me->data_size; 26 | const int left_val = *(int *) left_data; 27 | assert(val >= left_val); 28 | } 29 | if (right_child < size) { 30 | void *right_data = 31 | (char *) vector_storage + right_child * me->data_size; 32 | const int right_val = *(int *) right_data; 33 | assert(val >= right_val); 34 | } 35 | } 36 | } 37 | 38 | static int compare_int(const void *const one, const void *const two) 39 | { 40 | const int a = *(int *) one; 41 | const int b = *(int *) two; 42 | return a - b; 43 | } 44 | 45 | static int stub_priority_queue_push(priority_queue me, void *const data) 46 | { 47 | const int ret = priority_queue_push(me, data); 48 | priority_queue_verify(me); 49 | return ret; 50 | } 51 | 52 | static int stub_priority_queue_pop(void *const data, priority_queue me) 53 | { 54 | const int ret = priority_queue_pop(data, me); 55 | priority_queue_verify(me); 56 | return ret; 57 | } 58 | 59 | static void test_invalid_init(void) 60 | { 61 | assert(!priority_queue_init(0, compare_int)); 62 | assert(!priority_queue_init(sizeof(int), NULL)); 63 | } 64 | 65 | static void test_basic(void) 66 | { 67 | int item; 68 | int latest; 69 | size_t i; 70 | priority_queue me = priority_queue_init(sizeof(int), compare_int); 71 | assert(me); 72 | assert(priority_queue_size(me) == 0); 73 | assert(priority_queue_is_empty(me)); 74 | item = 0xfacade; 75 | assert(!priority_queue_pop(&item, me)); 76 | assert(item == 0xfacade); 77 | item = 5; 78 | stub_priority_queue_push(me, &item); 79 | item = 2; 80 | stub_priority_queue_push(me, &item); 81 | item = 7; 82 | stub_priority_queue_push(me, &item); 83 | item = 3; 84 | stub_priority_queue_push(me, &item); 85 | item = 4; 86 | stub_priority_queue_push(me, &item); 87 | item = 5; 88 | stub_priority_queue_push(me, &item); 89 | item = 9; 90 | stub_priority_queue_push(me, &item); 91 | item = 2; 92 | stub_priority_queue_push(me, &item); 93 | item = 3; 94 | stub_priority_queue_push(me, &item); 95 | item = -5; 96 | stub_priority_queue_push(me, &item); 97 | item = 7; 98 | stub_priority_queue_push(me, &item); 99 | item = 3; 100 | stub_priority_queue_push(me, &item); 101 | item = 4; 102 | stub_priority_queue_push(me, &item); 103 | item = 3; 104 | stub_priority_queue_push(me, &item); 105 | item = 11; 106 | stub_priority_queue_push(me, &item); 107 | item = 6; 108 | stub_priority_queue_push(me, &item); 109 | assert(priority_queue_size(me) == 16); 110 | assert(!priority_queue_is_empty(me)); 111 | item = 0xfacade; 112 | priority_queue_front(&item, me); 113 | assert(item == 11); 114 | item = 0xfacade; 115 | stub_priority_queue_pop(&item, me); 116 | assert(item == 11); 117 | assert(priority_queue_size(me) == 15); 118 | item = 0xfacade; 119 | priority_queue_front(&item, me); 120 | assert(item == 9); 121 | latest = item; 122 | for (i = 0; i < 15; i++) { 123 | stub_priority_queue_pop(&item, me); 124 | assert(item <= latest); 125 | latest = item; 126 | assert(priority_queue_size(me) == 15 - i - 1); 127 | } 128 | priority_queue_clear(me); 129 | assert(priority_queue_is_empty(me)); 130 | item = 0xfacade; 131 | assert(!priority_queue_front(&item, me)); 132 | assert(item == 0xfacade); 133 | assert(priority_queue_is_empty(me)); 134 | assert(!priority_queue_destroy(me)); 135 | } 136 | 137 | #if STUB_MALLOC 138 | static void test_init_out_of_memory(void) 139 | { 140 | fail_malloc = 1; 141 | assert(!priority_queue_init(sizeof(int), compare_int)); 142 | fail_malloc = 1; 143 | delay_fail_malloc = 1; 144 | assert(!priority_queue_init(sizeof(int), compare_int)); 145 | fail_malloc = 1; 146 | delay_fail_malloc = 2; 147 | assert(!priority_queue_init(sizeof(int), compare_int)); 148 | } 149 | #endif 150 | 151 | #if STUB_MALLOC 152 | static void test_push_out_of_memory(void) 153 | { 154 | int i; 155 | int get = 0xfacade; 156 | priority_queue me = priority_queue_init(sizeof(int), compare_int); 157 | for (i = 0; i < 16; i++) { 158 | assert(priority_queue_push(me, &i) == 0); 159 | } 160 | assert(priority_queue_size(me) == 16); 161 | fail_malloc = 1; 162 | assert(priority_queue_push(me, &get) == -ENOMEM); 163 | for (i = 0; i < 16; i++) { 164 | get = 0xfacade; 165 | assert(priority_queue_pop(&get, me)); 166 | assert(get == 15 - i); 167 | } 168 | assert(priority_queue_size(me) == 0); 169 | priority_queue_clear(me); 170 | for (i = 0; i < 12; i++) { 171 | assert(priority_queue_push(me, &i) == 0); 172 | } 173 | assert(priority_queue_size(me) == 12); 174 | fail_realloc = 1; 175 | assert(priority_queue_push(me, &get) == -ENOMEM); 176 | for (i = 0; i < 12; i++) { 177 | get = 0xfacade; 178 | assert(priority_queue_pop(&get, me)); 179 | assert(get == 11 - i); 180 | } 181 | assert(!priority_queue_destroy(me)); 182 | } 183 | #endif 184 | 185 | struct big_object { 186 | int n; 187 | double d; 188 | signed char c[8]; 189 | }; 190 | 191 | static int compare_big_object(const void *const one, const void *const two) 192 | { 193 | const struct big_object *const a = one; 194 | const struct big_object *const b = two; 195 | /* Bigger number = lower priority */ 196 | return b->n - a->n; 197 | } 198 | 199 | static void test_big_object(void) 200 | { 201 | int i; 202 | priority_queue me = priority_queue_init(sizeof(struct big_object), 203 | compare_big_object); 204 | assert(me); 205 | for (i = 0; i < 16; i++) { 206 | int j; 207 | struct big_object b; 208 | b.n = INT_MIN + i; 209 | b.d = i + 0.5; 210 | for (j = 0; j < 8; j++) { 211 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 212 | } 213 | assert(priority_queue_push(me, &b) == 0); 214 | b.n = -1; 215 | b.d = -1; 216 | for (j = 0; j < 8; j++) { 217 | b.c[j] = -1; 218 | } 219 | } 220 | for (i = 0; i < 16; i++) { 221 | int j; 222 | struct big_object b; 223 | assert(priority_queue_pop(&b, me) == 1); 224 | assert(b.n == INT_MIN + i); 225 | assert(b.d == i + 0.5); 226 | for (j = 0; j < 8; j++) { 227 | assert(b.c[j] == SCHAR_MIN + i + j); 228 | } 229 | } 230 | assert(!priority_queue_destroy(me)); 231 | } 232 | 233 | void test_priority_queue(void) 234 | { 235 | test_invalid_init(); 236 | test_basic(); 237 | #if STUB_MALLOC 238 | test_init_out_of_memory(); 239 | test_push_out_of_memory(); 240 | #endif 241 | test_big_object(); 242 | priority_queue_destroy(NULL); 243 | } 244 | -------------------------------------------------------------------------------- /tst/test_queue.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/queue.h" 3 | 4 | static void test_invalid_init(void) 5 | { 6 | assert(!queue_init(0)); 7 | } 8 | 9 | static void test_linear_operations(queue me) 10 | { 11 | int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 12 | int stuff; 13 | int get; 14 | int i; 15 | assert(queue_size(me) == 0); 16 | assert(queue_is_empty(me)); 17 | for (i = 0; i < 10; i++) { 18 | queue_push(me, &val[i]); 19 | get = 0; 20 | assert(queue_back(&get, me)); 21 | assert(get == val[i]); 22 | stuff = 0; 23 | assert(queue_front(&stuff, me)); 24 | assert(stuff == 1); 25 | } 26 | assert(queue_size(me) == 10); 27 | assert(!queue_is_empty(me)); 28 | } 29 | 30 | static void test_array_copy(queue me) 31 | { 32 | int get_arr[10] = {0}; 33 | int get; 34 | int i; 35 | queue_copy_to_array(get_arr, me); 36 | for (i = 0; i < 10; i++) { 37 | assert(get_arr[i] == i + 1); 38 | } 39 | for (i = 0; i < 9; i++) { 40 | get = 0; 41 | assert(queue_pop(&get, me)); 42 | assert(get == i + 1); 43 | } 44 | } 45 | 46 | static void test_array_trim(queue me) 47 | { 48 | int get; 49 | queue_trim(me); 50 | assert(queue_size(me) == 1); 51 | queue_clear(me); 52 | assert(queue_size(me) == 0); 53 | get = 0; 54 | assert(!queue_pop(&get, me)); 55 | assert(!queue_front(&get, me)); 56 | assert(!queue_back(&get, me)); 57 | } 58 | 59 | static void test_basic(void) 60 | { 61 | queue me = queue_init(sizeof(int)); 62 | assert(me); 63 | test_linear_operations(me); 64 | test_array_copy(me); 65 | test_array_trim(me); 66 | assert(!queue_destroy(me)); 67 | } 68 | 69 | static void test_large_alloc(void) 70 | { 71 | int old_size; 72 | int pop_count; 73 | int get; 74 | int i; 75 | queue me = queue_init(sizeof(int)); 76 | assert(me); 77 | for (i = 123; i < 123456; i++) { 78 | queue_push(me, &i); 79 | } 80 | old_size = queue_size(me); 81 | pop_count = 0; 82 | while (!queue_is_empty(me)) { 83 | queue_pop(&get, me); 84 | pop_count++; 85 | } 86 | assert(pop_count == old_size); 87 | assert(!queue_destroy(me)); 88 | } 89 | 90 | static void test_automated_trim(void) 91 | { 92 | queue me = queue_init(sizeof(int)); 93 | int get; 94 | int i; 95 | for (i = 0; i < 100; i++) { 96 | queue_push(me, &i); 97 | queue_pop(&get, me); 98 | } 99 | assert(!queue_destroy(me)); 100 | } 101 | 102 | struct pair { 103 | int cur_node; 104 | int cur_cost; 105 | }; 106 | 107 | static int test_puzzle(int start_node, int dest_node) 108 | { 109 | queue q = queue_init(sizeof(struct pair)); 110 | struct pair cur; 111 | cur.cur_node = start_node; 112 | cur.cur_cost = 0; 113 | assert(queue_is_empty(q)); 114 | queue_push(q, &cur); 115 | assert(queue_size(q) == 1); 116 | while (!queue_is_empty(q)) { 117 | int node; 118 | int cost; 119 | queue_pop(&cur, q); 120 | node = cur.cur_node; 121 | cost = cur.cur_cost; 122 | if (node > 2 * dest_node || node < 1) { 123 | continue; 124 | } 125 | if (node == dest_node) { 126 | queue_destroy(q); 127 | return cost; 128 | } 129 | cur.cur_cost = cost + 1; 130 | cur.cur_node = node - 1; 131 | queue_push(q, &cur); 132 | assert(cur.cur_cost == cost + 1); 133 | assert(cur.cur_node == node - 1); 134 | cur.cur_node = 2 * node; 135 | queue_push(q, &cur); 136 | assert(cur.cur_cost == cost + 1); 137 | assert(cur.cur_node == 2 * node); 138 | } 139 | queue_destroy(q); 140 | return -1; 141 | } 142 | 143 | struct big_object { 144 | int n; 145 | double d; 146 | signed char c[8]; 147 | }; 148 | 149 | static void test_big_object(void) 150 | { 151 | int i; 152 | queue me = queue_init(sizeof(struct big_object)); 153 | assert(me); 154 | for (i = 0; i < 16; i++) { 155 | int j; 156 | struct big_object b; 157 | b.n = INT_MIN + i; 158 | b.d = i + 0.5; 159 | for (j = 0; j < 8; j++) { 160 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 161 | } 162 | assert(queue_push(me, &b) == 0); 163 | b.n = -1; 164 | b.d = -1; 165 | for (j = 0; j < 8; j++) { 166 | b.c[j] = -1; 167 | } 168 | } 169 | for (i = 0; i < 16; i++) { 170 | int j; 171 | struct big_object b; 172 | assert(queue_pop(&b, me) == 1); 173 | assert(b.n == INT_MIN + i); 174 | assert(b.d == i + 0.5); 175 | for (j = 0; j < 8; j++) { 176 | assert(b.c[j] == SCHAR_MIN + i + j); 177 | } 178 | } 179 | assert(!queue_destroy(me)); 180 | } 181 | 182 | void test_queue(void) 183 | { 184 | test_invalid_init(); 185 | test_basic(); 186 | test_large_alloc(); 187 | test_automated_trim(); 188 | assert(test_puzzle(2, 5) == 4); 189 | assert(test_puzzle(2, 10) == 5); 190 | test_big_object(); 191 | queue_destroy(NULL); 192 | } 193 | -------------------------------------------------------------------------------- /tst/test_stack.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/stack.h" 3 | 4 | static void test_invalid_init(void) 5 | { 6 | assert(!stack_init(0)); 7 | } 8 | 9 | static void test_linear_operations(stack me) 10 | { 11 | int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 12 | int get; 13 | int i; 14 | assert(stack_size(me) == 0); 15 | assert(stack_is_empty(me)); 16 | for (i = 0; i < 10; i++) { 17 | stack_push(me, &val[i]); 18 | get = 0; 19 | assert(stack_top(&get, me)); 20 | assert(get == val[i]); 21 | } 22 | } 23 | 24 | static void test_array_copy(stack me) 25 | { 26 | int get_arr[10] = {0}; 27 | int get; 28 | int i; 29 | assert(stack_size(me) == 10); 30 | assert(!stack_is_empty(me)); 31 | stack_copy_to_array(get_arr, me); 32 | for (i = 0; i < 10; i++) { 33 | assert(get_arr[i] == i + 1); 34 | } 35 | for (i = 0; i < 9; i++) { 36 | get = 0; 37 | assert(stack_pop(&get, me)); 38 | assert(get == 10 - i); 39 | } 40 | stack_trim(me); 41 | assert(stack_size(me) == 1); 42 | stack_clear(me); 43 | assert(stack_size(me) == 0); 44 | get = 0; 45 | assert(!stack_pop(&get, me)); 46 | assert(!stack_top(&get, me)); 47 | } 48 | 49 | static void test_basic(void) 50 | { 51 | stack me = stack_init(sizeof(int)); 52 | assert(me); 53 | test_linear_operations(me); 54 | test_array_copy(me); 55 | assert(!stack_destroy(me)); 56 | } 57 | 58 | static void test_automated_trim(void) 59 | { 60 | stack me = stack_init(sizeof(int)); 61 | int get; 62 | int i; 63 | for (i = 0; i < 100; i++) { 64 | stack_push(me, &i); 65 | stack_pop(&get, me); 66 | } 67 | assert(!stack_destroy(me)); 68 | } 69 | 70 | struct big_object { 71 | int n; 72 | double d; 73 | signed char c[8]; 74 | }; 75 | 76 | static void test_big_object(void) 77 | { 78 | int i; 79 | stack me = stack_init(sizeof(struct big_object)); 80 | assert(me); 81 | for (i = 0; i < 16; i++) { 82 | int j; 83 | struct big_object b; 84 | b.n = INT_MIN + i; 85 | b.d = i + 0.5; 86 | for (j = 0; j < 8; j++) { 87 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 88 | } 89 | assert(stack_push(me, &b) == 0); 90 | b.n = -1; 91 | b.d = -1; 92 | for (j = 0; j < 8; j++) { 93 | b.c[j] = -1; 94 | } 95 | } 96 | for (i = 15; i >= 0; i--) { 97 | int j; 98 | struct big_object b; 99 | assert(stack_pop(&b, me) == 1); 100 | assert(b.n == INT_MIN + i); 101 | assert(b.d == i + 0.5); 102 | for (j = 0; j < 8; j++) { 103 | assert(b.c[j] == SCHAR_MIN + i + j); 104 | } 105 | } 106 | assert(!stack_destroy(me)); 107 | } 108 | 109 | void test_stack(void) 110 | { 111 | test_invalid_init(); 112 | test_basic(); 113 | test_automated_trim(); 114 | test_big_object(); 115 | stack_destroy(NULL); 116 | } 117 | -------------------------------------------------------------------------------- /tst/test_unordered_map.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/unordered_map.h" 3 | 4 | static int compare_int(const void *const one, const void *const two) 5 | { 6 | const int a = *(int *) one; 7 | const int b = *(int *) two; 8 | return a - b; 9 | } 10 | 11 | static int hash_count; 12 | 13 | static unsigned long hash_int(const void *const key) 14 | { 15 | unsigned long hash = 17; 16 | hash_count++; 17 | hash = 31 * hash + *(int *) key; 18 | return hash; 19 | } 20 | 21 | static unsigned long bad_hash_int(const void *const key) 22 | { 23 | (void) key; 24 | return 5; 25 | } 26 | 27 | static void test_invalid_init(void) 28 | { 29 | const size_t max_size = -1; 30 | assert(!unordered_map_init(0, sizeof(int), hash_int, compare_int)); 31 | assert(!unordered_map_init(sizeof(int), 0, hash_int, compare_int)); 32 | assert(!unordered_map_init(sizeof(int), sizeof(int), NULL, compare_int)); 33 | assert(!unordered_map_init(sizeof(int), sizeof(int), hash_int, NULL)); 34 | assert(!unordered_map_init(max_size, max_size, hash_int, compare_int)); 35 | assert(!unordered_map_init(1, max_size, hash_int, compare_int)); 36 | } 37 | 38 | static void test_put(unordered_map me) 39 | { 40 | int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; 41 | int key; 42 | int value; 43 | int i; 44 | int j; 45 | assert(unordered_map_size(me) == 0); 46 | assert(unordered_map_is_empty(me)); 47 | key = 4; 48 | value = 9; 49 | unordered_map_put(me, &key, &value); 50 | assert(unordered_map_size(me) == 1); 51 | value = 5; 52 | unordered_map_put(me, &key, &value); 53 | assert(unordered_map_size(me) == 1); 54 | assert(!unordered_map_is_empty(me)); 55 | assert(unordered_map_contains(me, &key)); 56 | value = 0xfacade; 57 | unordered_map_get(&value, me, &key); 58 | assert(value == 5); 59 | key = 7; 60 | assert(!unordered_map_contains(me, &key)); 61 | unordered_map_put(me, &key, &value); 62 | assert(unordered_map_size(me) == 2); 63 | assert(unordered_map_contains(me, &key)); 64 | for (i = 0; i < 10; i++) { 65 | unordered_map_put(me, &val_arr[i], &value); 66 | assert(unordered_map_contains(me, &val_arr[i])); 67 | } 68 | assert(unordered_map_size(me) == 9); 69 | for (i = 0; i < 10; i++) { 70 | assert(unordered_map_contains(me, &val_arr[i])); 71 | } 72 | for (i = -100; i < 100; i++) { 73 | int contains = 0; 74 | for (j = 0; j < 10; j++) { 75 | if (val_arr[j] == i) { 76 | contains = 1; 77 | } 78 | } 79 | assert(unordered_map_contains(me, &i) == contains); 80 | } 81 | } 82 | 83 | static void test_remove(unordered_map me) 84 | { 85 | int num = -3; 86 | assert(!unordered_map_remove(me, &num)); 87 | assert(unordered_map_size(me) == 9); 88 | assert(!unordered_map_contains(me, &num)); 89 | num = 6; 90 | assert(unordered_map_remove(me, &num)); 91 | assert(unordered_map_size(me) == 8); 92 | assert(!unordered_map_contains(me, &num)); 93 | num = 4; 94 | assert(unordered_map_remove(me, &num)); 95 | assert(unordered_map_size(me) == 7); 96 | assert(!unordered_map_contains(me, &num)); 97 | num = 7; 98 | assert(unordered_map_remove(me, &num)); 99 | assert(unordered_map_size(me) == 6); 100 | assert(!unordered_map_contains(me, &num)); 101 | num = 9; 102 | assert(unordered_map_remove(me, &num)); 103 | assert(unordered_map_size(me) == 5); 104 | assert(!unordered_map_contains(me, &num)); 105 | num = -5; 106 | assert(unordered_map_remove(me, &num)); 107 | assert(unordered_map_size(me) == 4); 108 | assert(!unordered_map_contains(me, &num)); 109 | num = 0; 110 | assert(unordered_map_remove(me, &num)); 111 | assert(unordered_map_size(me) == 3); 112 | assert(!unordered_map_contains(me, &num)); 113 | num = 1; 114 | assert(unordered_map_remove(me, &num)); 115 | assert(unordered_map_size(me) == 2); 116 | assert(!unordered_map_contains(me, &num)); 117 | num = 5; 118 | assert(unordered_map_remove(me, &num)); 119 | assert(unordered_map_size(me) == 1); 120 | assert(!unordered_map_contains(me, &num)); 121 | num = 2; 122 | assert(unordered_map_remove(me, &num)); 123 | assert(unordered_map_size(me) == 0); 124 | assert(!unordered_map_contains(me, &num)); 125 | } 126 | 127 | static void test_stress_remove(unordered_map me) 128 | { 129 | int value = 27; 130 | int i; 131 | for (i = 5000; i < 6000; i++) { 132 | unordered_map_put(me, &i, &value); 133 | assert(unordered_map_contains(me, &i)); 134 | } 135 | assert(unordered_map_size(me) == 1000); 136 | for (i = 5000; i < 6000; i++) { 137 | unordered_map_remove(me, &i); 138 | assert(!unordered_map_contains(me, &i)); 139 | } 140 | assert(unordered_map_size(me) == 0); 141 | assert(unordered_map_is_empty(me)); 142 | unordered_map_clear(me); 143 | assert(unordered_map_size(me) == 0); 144 | assert(unordered_map_is_empty(me)); 145 | } 146 | 147 | static void test_stress_clear(unordered_map me) 148 | { 149 | int value = 57; 150 | int key; 151 | int i; 152 | for (i = 5000; i < 6000; i++) { 153 | unordered_map_put(me, &i, &value); 154 | assert(unordered_map_contains(me, &i)); 155 | } 156 | assert(unordered_map_size(me) == 1000); 157 | hash_count = 0; 158 | unordered_map_rehash(me); 159 | assert(hash_count == 1000); 160 | unordered_map_clear(me); 161 | key = 0xfacade; 162 | assert(!unordered_map_remove(me, &key)); 163 | assert(unordered_map_size(me) == 0); 164 | assert(unordered_map_is_empty(me)); 165 | } 166 | 167 | static void test_basic(void) 168 | { 169 | unordered_map me = unordered_map_init(sizeof(int), sizeof(int), hash_int, 170 | compare_int); 171 | assert(me); 172 | test_put(me); 173 | test_remove(me); 174 | test_stress_remove(me); 175 | test_stress_clear(me); 176 | assert(!unordered_map_destroy(me)); 177 | } 178 | 179 | static void test_bad_hash(void) 180 | { 181 | int num; 182 | int key; 183 | int value; 184 | unordered_map me = unordered_map_init(sizeof(int), sizeof(int), 185 | bad_hash_int, compare_int); 186 | num = 1; 187 | unordered_map_put(me, &num, &num); 188 | num = 2; 189 | unordered_map_put(me, &num, &num); 190 | num = 3; 191 | unordered_map_put(me, &num, &num); 192 | num = 4; 193 | unordered_map_put(me, &num, &num); 194 | assert(unordered_map_size(me) == 4); 195 | unordered_map_put(me, &num, &num); 196 | assert(unordered_map_size(me) == 4); 197 | assert(unordered_map_remove(me, &num)); 198 | assert(!unordered_map_remove(me, &num)); 199 | assert(unordered_map_size(me) == 3); 200 | unordered_map_rehash(me); 201 | assert(unordered_map_size(me) == 3); 202 | key = 5; 203 | value = 0xfacade; 204 | assert(!unordered_map_get(&value, me, &key)); 205 | assert(value == 0xfacade); 206 | assert(!unordered_map_destroy(me)); 207 | } 208 | 209 | #if STUB_MALLOC 210 | static void test_init_out_of_memory(void) 211 | { 212 | fail_malloc = 1; 213 | assert(!unordered_map_init(sizeof(int), sizeof(int), bad_hash_int, 214 | compare_int)); 215 | fail_calloc = 1; 216 | assert(!unordered_map_init(sizeof(int), sizeof(int), bad_hash_int, 217 | compare_int)); 218 | } 219 | #endif 220 | 221 | #if STUB_MALLOC 222 | static void test_rehash_out_of_memory(void) 223 | { 224 | int key = 5; 225 | int value = 7; 226 | unordered_map me = unordered_map_init(sizeof(int), sizeof(int), 227 | bad_hash_int, compare_int); 228 | assert(me); 229 | unordered_map_put(me, &key, &value); 230 | assert(unordered_map_size(me) == 1); 231 | assert(unordered_map_contains(me, &key)); 232 | fail_calloc = 1; 233 | assert(unordered_map_rehash(me) == -ENOMEM); 234 | assert(unordered_map_size(me) == 1); 235 | assert(unordered_map_contains(me, &key)); 236 | assert(!unordered_map_destroy(me)); 237 | } 238 | #endif 239 | 240 | #if STUB_MALLOC 241 | static void test_put_out_of_memory(void) 242 | { 243 | int key = 5; 244 | int value = 7; 245 | unordered_map me = unordered_map_init(sizeof(int), sizeof(int), 246 | bad_hash_int, compare_int); 247 | assert(me); 248 | fail_malloc = 1; 249 | assert(unordered_map_put(me, &key, &value) == -ENOMEM); 250 | assert(unordered_map_put(me, &key, &value) == 0); 251 | key = 7; 252 | fail_malloc = 1; 253 | assert(unordered_map_put(me, &key, &value) == -ENOMEM); 254 | assert(!unordered_map_destroy(me)); 255 | } 256 | #endif 257 | 258 | #if STUB_MALLOC 259 | static void test_resize_out_of_memory(void) 260 | { 261 | int i; 262 | unordered_map me = unordered_map_init(sizeof(int), sizeof(int), hash_int, 263 | compare_int); 264 | for (i = 0; i < 11; i++) { 265 | assert(unordered_map_put(me, &i, &i) == 0); 266 | } 267 | assert(unordered_map_size(me) == 11); 268 | i++; 269 | fail_calloc = 1; 270 | assert(unordered_map_put(me, &i, &i) == -ENOMEM); 271 | assert(unordered_map_size(me) == 11); 272 | for (i = 0; i < 11; i++) { 273 | assert(unordered_map_contains(me, &i)); 274 | } 275 | assert(!unordered_map_destroy(me)); 276 | } 277 | #endif 278 | 279 | #if STUB_MALLOC 280 | static void test_clear_out_of_memory(void) 281 | { 282 | int key = 5; 283 | int value = 7; 284 | unordered_map me = unordered_map_init(sizeof(int), sizeof(int), hash_int, 285 | compare_int); 286 | assert(me); 287 | assert(unordered_map_put(me, &key, &value) == 0); 288 | assert(unordered_map_size(me) == 1); 289 | assert(unordered_map_contains(me, &key)); 290 | fail_calloc = 1; 291 | assert(unordered_map_clear(me) == -ENOMEM); 292 | assert(unordered_map_size(me) == 1); 293 | assert(unordered_map_contains(me, &key)); 294 | assert(!unordered_map_destroy(me)); 295 | } 296 | #endif 297 | 298 | struct big_object { 299 | int n; 300 | double d; 301 | signed char c[8]; 302 | }; 303 | 304 | static int compare_big_object(const void *const one, const void *const two) 305 | { 306 | const struct big_object *const a = one; 307 | const struct big_object *const b = two; 308 | return a->n - b->n; 309 | } 310 | 311 | static void test_big_object(void) 312 | { 313 | int i; 314 | unordered_map me = unordered_map_init(sizeof(int), 315 | sizeof(struct big_object), 316 | bad_hash_int, compare_big_object); 317 | assert(me); 318 | for (i = 0; i < 16; i++) { 319 | int j; 320 | struct big_object b; 321 | b.n = INT_MIN + i; 322 | b.d = i + 0.5; 323 | for (j = 0; j < 8; j++) { 324 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 325 | } 326 | assert(unordered_map_put(me, &i, &b) == 0); 327 | b.n = -1; 328 | b.d = -1; 329 | for (j = 0; j < 8; j++) { 330 | b.c[j] = -1; 331 | } 332 | } 333 | for (i = 0; i < 16; i++) { 334 | int j; 335 | struct big_object b; 336 | assert(unordered_map_get(&b, me, &i) == 1); 337 | assert(b.n == INT_MIN + i); 338 | assert(b.d == i + 0.5); 339 | for (j = 0; j < 8; j++) { 340 | assert(b.c[j] == SCHAR_MIN + i + j); 341 | } 342 | } 343 | assert(!unordered_map_destroy(me)); 344 | } 345 | 346 | void test_unordered_map(void) 347 | { 348 | test_invalid_init(); 349 | test_basic(); 350 | test_bad_hash(); 351 | #if STUB_MALLOC 352 | test_init_out_of_memory(); 353 | test_rehash_out_of_memory(); 354 | test_put_out_of_memory(); 355 | test_resize_out_of_memory(); 356 | test_clear_out_of_memory(); 357 | #endif 358 | test_big_object(); 359 | unordered_map_destroy(NULL); 360 | } 361 | -------------------------------------------------------------------------------- /tst/test_unordered_multiset.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/unordered_multiset.h" 3 | 4 | static int compare_int(const void *const one, const void *const two) 5 | { 6 | const int a = *(int *) one; 7 | const int b = *(int *) two; 8 | return a - b; 9 | } 10 | 11 | static int hash_count; 12 | 13 | static unsigned long hash_int(const void *const key) 14 | { 15 | unsigned long hash = 17; 16 | hash_count++; 17 | hash = 31 * hash + *(int *) key; 18 | return hash; 19 | } 20 | 21 | static unsigned long bad_hash_int(const void *const key) 22 | { 23 | (void) key; 24 | return 5; 25 | } 26 | 27 | static void test_invalid_init(void) 28 | { 29 | const size_t max_size = -1; 30 | assert(!unordered_multiset_init(0, hash_int, compare_int)); 31 | assert(!unordered_multiset_init(sizeof(int), NULL, compare_int)); 32 | assert(!unordered_multiset_init(sizeof(int), hash_int, NULL)); 33 | assert(!unordered_multiset_init(max_size, hash_int, compare_int)); 34 | } 35 | 36 | static void test_put(unordered_multiset me) 37 | { 38 | int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; 39 | int key; 40 | int i; 41 | int j; 42 | assert(unordered_multiset_size(me) == 0); 43 | assert(unordered_multiset_is_empty(me)); 44 | key = 4; 45 | unordered_multiset_put(me, &key); 46 | assert(unordered_multiset_size(me) == 1); 47 | unordered_multiset_put(me, &key); 48 | assert(unordered_multiset_size(me) == 2); 49 | assert(!unordered_multiset_is_empty(me)); 50 | assert(unordered_multiset_contains(me, &key)); 51 | key = 7; 52 | assert(!unordered_multiset_contains(me, &key)); 53 | unordered_multiset_put(me, &key); 54 | assert(unordered_multiset_size(me) == 3); 55 | assert(unordered_multiset_contains(me, &key)); 56 | unordered_multiset_remove(me, &key); 57 | assert(unordered_multiset_size(me) == 2); 58 | assert(!unordered_multiset_contains(me, &key)); 59 | key = 4; 60 | unordered_multiset_remove(me, &key); 61 | assert(unordered_multiset_size(me) == 1); 62 | unordered_multiset_remove(me, &key); 63 | assert(unordered_multiset_size(me) == 0); 64 | for (i = 0; i < 10; i++) { 65 | unordered_multiset_put(me, &val_arr[i]); 66 | assert(unordered_multiset_contains(me, &val_arr[i])); 67 | } 68 | assert(unordered_multiset_size(me) == 10); 69 | for (i = 0; i < 10; i++) { 70 | assert(unordered_multiset_contains(me, &val_arr[i])); 71 | } 72 | for (i = -100; i < 100; i++) { 73 | int contains = 0; 74 | for (j = 0; j < 10; j++) { 75 | if (val_arr[j] == i) { 76 | contains = 1; 77 | } 78 | } 79 | assert(unordered_multiset_contains(me, &i) == contains); 80 | } 81 | } 82 | 83 | static void test_remove(unordered_multiset me) 84 | { 85 | int num = -3; 86 | assert(!unordered_multiset_remove(me, &num)); 87 | assert(unordered_multiset_size(me) == 10); 88 | assert(!unordered_multiset_contains(me, &num)); 89 | num = 6; 90 | assert(unordered_multiset_remove(me, &num)); 91 | assert(unordered_multiset_size(me) == 9); 92 | assert(!unordered_multiset_contains(me, &num)); 93 | num = 4; 94 | assert(unordered_multiset_remove(me, &num)); 95 | assert(unordered_multiset_size(me) == 8); 96 | assert(!unordered_multiset_contains(me, &num)); 97 | num = 7; 98 | assert(unordered_multiset_remove(me, &num)); 99 | assert(unordered_multiset_size(me) == 7); 100 | assert(!unordered_multiset_contains(me, &num)); 101 | num = 9; 102 | assert(unordered_multiset_remove(me, &num)); 103 | assert(unordered_multiset_size(me) == 6); 104 | assert(!unordered_multiset_contains(me, &num)); 105 | num = -5; 106 | assert(unordered_multiset_remove(me, &num)); 107 | assert(unordered_multiset_size(me) == 5); 108 | assert(!unordered_multiset_contains(me, &num)); 109 | num = 0; 110 | assert(unordered_multiset_remove(me, &num)); 111 | assert(unordered_multiset_size(me) == 4); 112 | assert(!unordered_multiset_contains(me, &num)); 113 | num = 1; 114 | assert(unordered_multiset_remove(me, &num)); 115 | assert(unordered_multiset_size(me) == 3); 116 | assert(!unordered_multiset_contains(me, &num)); 117 | num = 5; 118 | assert(unordered_multiset_remove(me, &num)); 119 | assert(unordered_multiset_size(me) == 2); 120 | assert(unordered_multiset_contains(me, &num)); 121 | num = 2; 122 | assert(unordered_multiset_remove(me, &num)); 123 | assert(unordered_multiset_size(me) == 1); 124 | assert(!unordered_multiset_contains(me, &num)); 125 | num = 5; 126 | assert(unordered_multiset_remove(me, &num)); 127 | assert(unordered_multiset_size(me) == 0); 128 | assert(!unordered_multiset_contains(me, &num)); 129 | } 130 | 131 | static void test_stress_remove(unordered_multiset me) 132 | { 133 | int i; 134 | for (i = 4000; i < 6000; i++) { 135 | unordered_multiset_put(me, &i); 136 | assert(unordered_multiset_contains(me, &i)); 137 | } 138 | assert(unordered_multiset_size(me) == 2000); 139 | for (i = 4000; i < 6000; i++) { 140 | unordered_multiset_remove(me, &i); 141 | assert(!unordered_multiset_contains(me, &i)); 142 | } 143 | assert(unordered_multiset_size(me) == 0); 144 | assert(unordered_multiset_is_empty(me)); 145 | unordered_multiset_clear(me); 146 | assert(unordered_multiset_size(me) == 0); 147 | assert(unordered_multiset_is_empty(me)); 148 | } 149 | 150 | static void test_stress_clear(unordered_multiset me) 151 | { 152 | int key; 153 | int i; 154 | for (i = 5000; i < 6000; i++) { 155 | unordered_multiset_put(me, &i); 156 | assert(unordered_multiset_contains(me, &i)); 157 | } 158 | assert(unordered_multiset_size(me) == 1000); 159 | hash_count = 0; 160 | unordered_multiset_rehash(me); 161 | assert(hash_count == 1000); 162 | unordered_multiset_clear(me); 163 | key = 0xfacade; 164 | assert(!unordered_multiset_remove(me, &key)); 165 | assert(unordered_multiset_size(me) == 0); 166 | assert(unordered_multiset_is_empty(me)); 167 | key = 5; 168 | unordered_multiset_put(me, &key); 169 | assert(unordered_multiset_size(me) == 1); 170 | key = 7; 171 | for (i = 0; i < 10; i++) { 172 | unordered_multiset_put(me, &key); 173 | } 174 | assert(unordered_multiset_size(me) == 11); 175 | unordered_multiset_remove_all(me, &key); 176 | assert(unordered_multiset_size(me) == 1); 177 | } 178 | 179 | static void test_basic(void) 180 | { 181 | unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, 182 | compare_int); 183 | assert(me); 184 | test_put(me); 185 | test_remove(me); 186 | test_stress_remove(me); 187 | test_stress_clear(me); 188 | assert(!unordered_multiset_destroy(me)); 189 | } 190 | 191 | static void test_bad_hash(void) 192 | { 193 | int i; 194 | int num; 195 | unordered_multiset me = unordered_multiset_init(sizeof(int), bad_hash_int, 196 | compare_int); 197 | assert(me); 198 | num = 1; 199 | unordered_multiset_put(me, &num); 200 | num = 2; 201 | unordered_multiset_put(me, &num); 202 | num = 3; 203 | unordered_multiset_put(me, &num); 204 | assert(unordered_multiset_size(me) == 3); 205 | unordered_multiset_put(me, &num); 206 | assert(unordered_multiset_size(me) == 4); 207 | num = 4; 208 | unordered_multiset_put(me, &num); 209 | assert(unordered_multiset_size(me) == 5); 210 | assert(unordered_multiset_remove(me, &num)); 211 | assert(!unordered_multiset_remove(me, &num)); 212 | assert(unordered_multiset_size(me) == 4); 213 | unordered_multiset_rehash(me); 214 | assert(unordered_multiset_size(me) == 4); 215 | for (i = 3; i > 0; i--) { 216 | assert(unordered_multiset_remove(me, &i)); 217 | } 218 | assert(!unordered_multiset_destroy(me)); 219 | } 220 | 221 | static void test_collision(void) 222 | { 223 | int num; 224 | unordered_multiset me = unordered_multiset_init(sizeof(int), bad_hash_int, 225 | compare_int); 226 | assert(me); 227 | num = 1; 228 | unordered_multiset_put(me, &num); 229 | num = 2; 230 | unordered_multiset_put(me, &num); 231 | num = 3; 232 | unordered_multiset_put(me, &num); 233 | assert(unordered_multiset_size(me) == 3); 234 | unordered_multiset_put(me, &num); 235 | assert(unordered_multiset_size(me) == 4); 236 | num = 4; 237 | unordered_multiset_put(me, &num); 238 | assert(unordered_multiset_size(me) == 5); 239 | assert(unordered_multiset_remove_all(me, &num)); 240 | assert(!unordered_multiset_remove_all(me, &num)); 241 | assert(unordered_multiset_size(me) == 4); 242 | unordered_multiset_rehash(me); 243 | assert(unordered_multiset_size(me) == 4); 244 | unordered_multiset_clear(me); 245 | assert(unordered_multiset_size(me) == 0); 246 | assert(!unordered_multiset_remove_all(me, &num)); 247 | assert(unordered_multiset_size(me) == 0); 248 | assert(!unordered_multiset_destroy(me)); 249 | } 250 | 251 | #if STUB_MALLOC 252 | static void test_init_out_of_memory(void) 253 | { 254 | fail_malloc = 1; 255 | assert(!unordered_multiset_init(sizeof(int), hash_int, compare_int)); 256 | fail_calloc = 1; 257 | assert(!unordered_multiset_init(sizeof(int), hash_int, compare_int)); 258 | } 259 | #endif 260 | 261 | #if STUB_MALLOC 262 | static void test_rehash_out_of_memory(void) 263 | { 264 | int key = 5; 265 | unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, 266 | compare_int); 267 | assert(me); 268 | unordered_multiset_put(me, &key); 269 | assert(unordered_multiset_size(me) == 1); 270 | assert(unordered_multiset_contains(me, &key)); 271 | fail_calloc = 1; 272 | assert(unordered_multiset_rehash(me) == -ENOMEM); 273 | assert(unordered_multiset_size(me) == 1); 274 | assert(unordered_multiset_contains(me, &key)); 275 | assert(!unordered_multiset_destroy(me)); 276 | } 277 | #endif 278 | 279 | #if STUB_MALLOC 280 | static void test_put_out_of_memory(void) 281 | { 282 | int key = 5; 283 | unordered_multiset me = unordered_multiset_init(sizeof(int), bad_hash_int, 284 | compare_int); 285 | assert(me); 286 | fail_malloc = 1; 287 | assert(unordered_multiset_put(me, &key) == -ENOMEM); 288 | fail_malloc = 1; 289 | assert(unordered_multiset_put(me, &key) == -ENOMEM); 290 | assert(unordered_multiset_put(me, &key) == 0); 291 | key = 7; 292 | fail_malloc = 1; 293 | assert(unordered_multiset_put(me, &key) == -ENOMEM); 294 | fail_malloc = 1; 295 | assert(unordered_multiset_put(me, &key) == -ENOMEM); 296 | assert(!unordered_multiset_destroy(me)); 297 | } 298 | #endif 299 | 300 | #if STUB_MALLOC 301 | static void test_resize_out_of_memory(void) 302 | { 303 | int i; 304 | unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, 305 | compare_int); 306 | for (i = 0; i < 11; i++) { 307 | assert(unordered_multiset_put(me, &i) == 0); 308 | } 309 | assert(unordered_multiset_size(me) == 11); 310 | i++; 311 | fail_calloc = 1; 312 | assert(unordered_multiset_put(me, &i) == -ENOMEM); 313 | assert(unordered_multiset_size(me) == 11); 314 | for (i = 0; i < 11; i++) { 315 | assert(unordered_multiset_contains(me, &i)); 316 | } 317 | assert(!unordered_multiset_destroy(me)); 318 | } 319 | #endif 320 | 321 | #if STUB_MALLOC 322 | static void test_clear_out_of_memory(void) 323 | { 324 | int key = 5; 325 | unordered_multiset me = unordered_multiset_init(sizeof(int), hash_int, 326 | compare_int); 327 | assert(me); 328 | assert(unordered_multiset_put(me, &key) == 0); 329 | assert(unordered_multiset_size(me) == 1); 330 | assert(unordered_multiset_contains(me, &key)); 331 | fail_calloc = 1; 332 | assert(unordered_multiset_clear(me) == -ENOMEM); 333 | assert(unordered_multiset_size(me) == 1); 334 | assert(unordered_multiset_contains(me, &key)); 335 | assert(!unordered_multiset_destroy(me)); 336 | } 337 | #endif 338 | 339 | struct big_object { 340 | int n; 341 | double d; 342 | signed char c[8]; 343 | }; 344 | 345 | static int compare_big_object(const void *const one, const void *const two) 346 | { 347 | const struct big_object *const a = one; 348 | const struct big_object *const b = two; 349 | return a->n - b->n; 350 | } 351 | 352 | static void test_big_object(void) 353 | { 354 | int i; 355 | unordered_multiset me = unordered_multiset_init(sizeof(struct big_object), 356 | bad_hash_int, 357 | compare_big_object); 358 | assert(me); 359 | for (i = 0; i < 16; i++) { 360 | int j; 361 | struct big_object b; 362 | b.n = INT_MIN + i; 363 | b.d = i + 0.5; 364 | for (j = 0; j < 8; j++) { 365 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 366 | } 367 | assert(unordered_multiset_put(me, &b) == 0); 368 | b.n = -1; 369 | b.d = -1; 370 | for (j = 0; j < 8; j++) { 371 | b.c[j] = -1; 372 | } 373 | } 374 | for (i = 0; i < 16; i++) { 375 | int j; 376 | struct big_object b; 377 | b.n = INT_MIN + i; 378 | b.d = i + 0.5; 379 | for (j = 0; j < 8; j++) { 380 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 381 | } 382 | assert(unordered_multiset_contains(me, &b) == 1); 383 | assert(b.n == INT_MIN + i); 384 | assert(b.d == i + 0.5); 385 | for (j = 0; j < 8; j++) { 386 | assert(b.c[j] == SCHAR_MIN + i + j); 387 | } 388 | } 389 | assert(!unordered_multiset_destroy(me)); 390 | } 391 | 392 | void test_unordered_multiset(void) 393 | { 394 | test_invalid_init(); 395 | test_basic(); 396 | test_bad_hash(); 397 | test_collision(); 398 | #if STUB_MALLOC 399 | test_init_out_of_memory(); 400 | test_rehash_out_of_memory(); 401 | test_put_out_of_memory(); 402 | test_resize_out_of_memory(); 403 | test_clear_out_of_memory(); 404 | #endif 405 | test_big_object(); 406 | unordered_multiset_destroy(NULL); 407 | } 408 | -------------------------------------------------------------------------------- /tst/test_unordered_set.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/unordered_set.h" 3 | 4 | static int compare_int(const void *const one, const void *const two) 5 | { 6 | const int a = *(int *) one; 7 | const int b = *(int *) two; 8 | return a - b; 9 | } 10 | 11 | static int hash_count; 12 | 13 | static unsigned long hash_int(const void *const key) 14 | { 15 | unsigned long hash = 17; 16 | hash_count++; 17 | hash = 31 * hash + *(int *) key; 18 | return hash; 19 | } 20 | 21 | static unsigned long bad_hash_int(const void *const key) 22 | { 23 | (void) key; 24 | return 5; 25 | } 26 | 27 | static void test_invalid_init(void) 28 | { 29 | const size_t max_size = -1; 30 | assert(!unordered_set_init(0, hash_int, compare_int)); 31 | assert(!unordered_set_init(sizeof(int), NULL, compare_int)); 32 | assert(!unordered_set_init(sizeof(int), hash_int, NULL)); 33 | assert(!unordered_set_init(max_size, hash_int, compare_int)); 34 | } 35 | 36 | static void test_put(unordered_set me) 37 | { 38 | int val_arr[10] = {5, 9, 4, -5, 0, 6, 1, 5, 7, 2}; 39 | int key; 40 | int i; 41 | int j; 42 | assert(unordered_set_size(me) == 0); 43 | assert(unordered_set_is_empty(me)); 44 | key = 4; 45 | unordered_set_put(me, &key); 46 | assert(unordered_set_size(me) == 1); 47 | unordered_set_put(me, &key); 48 | assert(unordered_set_size(me) == 1); 49 | assert(!unordered_set_is_empty(me)); 50 | assert(unordered_set_contains(me, &key)); 51 | key = 7; 52 | assert(!unordered_set_contains(me, &key)); 53 | unordered_set_put(me, &key); 54 | assert(unordered_set_size(me) == 2); 55 | assert(unordered_set_contains(me, &key)); 56 | for (i = 0; i < 10; i++) { 57 | unordered_set_put(me, &val_arr[i]); 58 | assert(unordered_set_contains(me, &val_arr[i])); 59 | } 60 | assert(unordered_set_size(me) == 9); 61 | for (i = 0; i < 10; i++) { 62 | assert(unordered_set_contains(me, &val_arr[i])); 63 | } 64 | for (i = -100; i < 100; i++) { 65 | int contains = 0; 66 | for (j = 0; j < 10; j++) { 67 | if (val_arr[j] == i) { 68 | contains = 1; 69 | } 70 | } 71 | assert(unordered_set_contains(me, &i) == contains); 72 | } 73 | } 74 | 75 | static void test_remove(unordered_set me) 76 | { 77 | int num = -3; 78 | assert(!unordered_set_remove(me, &num)); 79 | assert(unordered_set_size(me) == 9); 80 | assert(!unordered_set_contains(me, &num)); 81 | num = 6; 82 | assert(unordered_set_remove(me, &num)); 83 | assert(unordered_set_size(me) == 8); 84 | assert(!unordered_set_contains(me, &num)); 85 | num = 4; 86 | assert(unordered_set_remove(me, &num)); 87 | assert(unordered_set_size(me) == 7); 88 | assert(!unordered_set_contains(me, &num)); 89 | num = 7; 90 | assert(unordered_set_remove(me, &num)); 91 | assert(unordered_set_size(me) == 6); 92 | assert(!unordered_set_contains(me, &num)); 93 | num = 9; 94 | assert(unordered_set_remove(me, &num)); 95 | assert(unordered_set_size(me) == 5); 96 | assert(!unordered_set_contains(me, &num)); 97 | num = -5; 98 | assert(unordered_set_remove(me, &num)); 99 | assert(unordered_set_size(me) == 4); 100 | assert(!unordered_set_contains(me, &num)); 101 | num = 0; 102 | assert(unordered_set_remove(me, &num)); 103 | assert(unordered_set_size(me) == 3); 104 | assert(!unordered_set_contains(me, &num)); 105 | num = 1; 106 | assert(unordered_set_remove(me, &num)); 107 | assert(unordered_set_size(me) == 2); 108 | assert(!unordered_set_contains(me, &num)); 109 | num = 5; 110 | assert(unordered_set_remove(me, &num)); 111 | assert(unordered_set_size(me) == 1); 112 | assert(!unordered_set_contains(me, &num)); 113 | num = 2; 114 | assert(unordered_set_remove(me, &num)); 115 | assert(unordered_set_size(me) == 0); 116 | assert(!unordered_set_contains(me, &num)); 117 | } 118 | 119 | static void test_stress_remove(unordered_set me) 120 | { 121 | int i; 122 | for (i = 5000; i < 6000; i++) { 123 | unordered_set_put(me, &i); 124 | assert(unordered_set_contains(me, &i)); 125 | } 126 | assert(unordered_set_size(me) == 1000); 127 | for (i = 5000; i < 6000; i++) { 128 | unordered_set_remove(me, &i); 129 | assert(!unordered_set_contains(me, &i)); 130 | } 131 | assert(unordered_set_size(me) == 0); 132 | assert(unordered_set_is_empty(me)); 133 | unordered_set_clear(me); 134 | assert(unordered_set_size(me) == 0); 135 | assert(unordered_set_is_empty(me)); 136 | } 137 | 138 | static void test_stress_clear(unordered_set me) 139 | { 140 | int i; 141 | int p = 0xfacade; 142 | for (i = 5000; i < 6000; i++) { 143 | unordered_set_put(me, &i); 144 | assert(unordered_set_contains(me, &i)); 145 | } 146 | assert(unordered_set_size(me) == 1000); 147 | hash_count = 0; 148 | unordered_set_rehash(me); 149 | assert(hash_count == 1000); 150 | unordered_set_clear(me); 151 | assert(!unordered_set_remove(me, &p)); 152 | assert(unordered_set_size(me) == 0); 153 | assert(unordered_set_is_empty(me)); 154 | } 155 | 156 | static void test_basic(void) 157 | { 158 | unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); 159 | assert(me); 160 | test_put(me); 161 | test_remove(me); 162 | test_stress_remove(me); 163 | test_stress_clear(me); 164 | assert(!unordered_set_destroy(me)); 165 | } 166 | 167 | static void test_bad_hash(void) 168 | { 169 | int i; 170 | int num; 171 | unordered_set me = unordered_set_init(sizeof(int), bad_hash_int, 172 | compare_int); 173 | assert(me); 174 | num = 1; 175 | unordered_set_put(me, &num); 176 | num = 2; 177 | unordered_set_put(me, &num); 178 | num = 3; 179 | unordered_set_put(me, &num); 180 | num = 4; 181 | unordered_set_put(me, &num); 182 | assert(unordered_set_size(me) == 4); 183 | unordered_set_put(me, &num); 184 | assert(unordered_set_size(me) == 4); 185 | assert(unordered_set_remove(me, &num)); 186 | assert(!unordered_set_remove(me, &num)); 187 | assert(unordered_set_size(me) == 3); 188 | unordered_set_rehash(me); 189 | assert(unordered_set_size(me) == 3); 190 | for (i = 2; i > 0; i--) { 191 | assert(unordered_set_remove(me, &i)); 192 | } 193 | assert(!unordered_set_destroy(me)); 194 | } 195 | 196 | #if STUB_MALLOC 197 | static void test_init_out_of_memory(void) 198 | { 199 | fail_malloc = 1; 200 | assert(!unordered_set_init(sizeof(int), hash_int, compare_int)); 201 | fail_calloc = 1; 202 | assert(!unordered_set_init(sizeof(int), hash_int, compare_int)); 203 | } 204 | #endif 205 | 206 | #if STUB_MALLOC 207 | static void test_rehash_out_of_memory(void) 208 | { 209 | int key = 5; 210 | unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); 211 | assert(me); 212 | unordered_set_put(me, &key); 213 | assert(unordered_set_size(me) == 1); 214 | assert(unordered_set_contains(me, &key)); 215 | fail_calloc = 1; 216 | assert(unordered_set_rehash(me) == -ENOMEM); 217 | assert(unordered_set_size(me) == 1); 218 | assert(unordered_set_contains(me, &key)); 219 | assert(!unordered_set_destroy(me)); 220 | } 221 | #endif 222 | 223 | #if STUB_MALLOC 224 | static void test_put_out_of_memory(void) 225 | { 226 | int key = 5; 227 | unordered_set me = unordered_set_init(sizeof(int), bad_hash_int, 228 | compare_int); 229 | assert(me); 230 | fail_malloc = 1; 231 | assert(unordered_set_put(me, &key) == -ENOMEM); 232 | fail_malloc = 1; 233 | assert(unordered_set_put(me, &key) == -ENOMEM); 234 | assert(unordered_set_put(me, &key) == 0); 235 | key = 7; 236 | fail_malloc = 1; 237 | assert(unordered_set_put(me, &key) == -ENOMEM); 238 | fail_malloc = 1; 239 | assert(unordered_set_put(me, &key) == -ENOMEM); 240 | assert(!unordered_set_destroy(me)); 241 | } 242 | #endif 243 | 244 | #if STUB_MALLOC 245 | static void test_resize_out_of_memory(void) 246 | { 247 | int i; 248 | unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); 249 | for (i = 0; i < 11; i++) { 250 | assert(unordered_set_put(me, &i) == 0); 251 | } 252 | assert(unordered_set_size(me) == 11); 253 | i++; 254 | fail_calloc = 1; 255 | assert(unordered_set_put(me, &i) == -ENOMEM); 256 | assert(unordered_set_size(me) == 11); 257 | for (i = 0; i < 11; i++) { 258 | assert(unordered_set_contains(me, &i)); 259 | } 260 | assert(!unordered_set_destroy(me)); 261 | } 262 | #endif 263 | 264 | #if STUB_MALLOC 265 | static void test_clear_out_of_memory(void) 266 | { 267 | int key = 5; 268 | unordered_set me = unordered_set_init(sizeof(int), hash_int, compare_int); 269 | assert(me); 270 | assert(unordered_set_put(me, &key) == 0); 271 | assert(unordered_set_size(me) == 1); 272 | assert(unordered_set_contains(me, &key)); 273 | fail_calloc = 1; 274 | assert(unordered_set_clear(me) == -ENOMEM); 275 | assert(unordered_set_size(me) == 1); 276 | assert(unordered_set_contains(me, &key)); 277 | assert(!unordered_set_destroy(me)); 278 | } 279 | #endif 280 | 281 | struct big_object { 282 | int n; 283 | double d; 284 | signed char c[8]; 285 | }; 286 | 287 | static int compare_big_object(const void *const one, const void *const two) 288 | { 289 | const struct big_object *const a = one; 290 | const struct big_object *const b = two; 291 | return a->n - b->n; 292 | } 293 | 294 | static void test_big_object(void) 295 | { 296 | int i; 297 | unordered_set me = unordered_set_init(sizeof(struct big_object), 298 | bad_hash_int, compare_big_object); 299 | assert(me); 300 | for (i = 0; i < 16; i++) { 301 | int j; 302 | struct big_object b; 303 | b.n = INT_MIN + i; 304 | b.d = i + 0.5; 305 | for (j = 0; j < 8; j++) { 306 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 307 | } 308 | assert(unordered_set_put(me, &b) == 0); 309 | b.n = -1; 310 | b.d = -1; 311 | for (j = 0; j < 8; j++) { 312 | b.c[j] = -1; 313 | } 314 | } 315 | for (i = 0; i < 16; i++) { 316 | int j; 317 | struct big_object b; 318 | b.n = INT_MIN + i; 319 | b.d = i + 0.5; 320 | for (j = 0; j < 8; j++) { 321 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 322 | } 323 | assert(unordered_set_contains(me, &b) == 1); 324 | assert(b.n == INT_MIN + i); 325 | assert(b.d == i + 0.5); 326 | for (j = 0; j < 8; j++) { 327 | assert(b.c[j] == SCHAR_MIN + i + j); 328 | } 329 | } 330 | assert(!unordered_set_destroy(me)); 331 | } 332 | 333 | void test_unordered_set(void) 334 | { 335 | test_invalid_init(); 336 | test_basic(); 337 | test_bad_hash(); 338 | #if STUB_MALLOC 339 | test_init_out_of_memory(); 340 | test_rehash_out_of_memory(); 341 | test_put_out_of_memory(); 342 | test_resize_out_of_memory(); 343 | test_clear_out_of_memory(); 344 | #endif 345 | test_big_object(); 346 | unordered_set_destroy(NULL); 347 | } 348 | -------------------------------------------------------------------------------- /tst/test_vector.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "../src/include/vector.h" 3 | 4 | static void test_invalid_init(void) 5 | { 6 | const size_t compare_int = -1; 7 | assert(!vector_init(0)); 8 | assert(!vector_init(compare_int)); 9 | } 10 | 11 | static void test_adding(vector me) 12 | { 13 | int val[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 14 | int get_arr[10] = {0}; 15 | int *data; 16 | int get; 17 | int i; 18 | for (i = 0; i < 10; i++) { 19 | vector_add_first(me, &val[i]); 20 | get = 0; 21 | vector_get_first(&get, me); 22 | assert(get == val[i]); 23 | } 24 | assert(vector_size(me) == 10); 25 | assert(!vector_is_empty(me)); 26 | vector_copy_to_array(get_arr, me); 27 | for (i = 0; i < 10; i++) { 28 | get = 0; 29 | vector_get_at(&get, me, i); 30 | assert(get == val[9 - i]); 31 | assert(get_arr[i] == val[9 - i]); 32 | } 33 | data = vector_get_data(me); 34 | for (i = 0; i < 10; i++) { 35 | assert(data[i] == val[9 - i]); 36 | } 37 | assert(vector_capacity(me) >= vector_size(me)); 38 | } 39 | 40 | static void test_trim(vector me) 41 | { 42 | int trimmed[5] = {0}; 43 | int i; 44 | vector_trim(me); 45 | vector_reserve(me, 3); 46 | for (i = 0; i < 7; i++) { 47 | vector_remove_last(me); 48 | } 49 | vector_copy_to_array(trimmed, me); 50 | assert(vector_size(me) == 3); 51 | for (i = 0; i < 3; i++) { 52 | assert(10 - i == trimmed[i]); 53 | } 54 | } 55 | 56 | static void test_linear_operations(vector me) 57 | { 58 | int arr[3] = {0}; 59 | int get; 60 | int set; 61 | int add = 3; 62 | assert(vector_size(me) == 3); 63 | vector_add_last(me, &add); 64 | add = -1; 65 | vector_add_at(me, 1, &add); 66 | add = -2; 67 | vector_add_last(me, &add); 68 | assert(vector_size(me) == 6); 69 | get = 0xfacade; 70 | vector_get_first(&get, me); 71 | assert(get == 10); 72 | get = 0xfacade; 73 | vector_get_at(&get, me, 0); 74 | assert(get == 10); 75 | vector_get_at(&get, me, 1); 76 | assert(get == -1); 77 | vector_get_at(&get, me, 2); 78 | assert(get == 9); 79 | vector_get_at(&get, me, 3); 80 | assert(get == 8); 81 | vector_get_at(&get, me, 4); 82 | assert(get == 3); 83 | vector_get_at(&get, me, 5); 84 | assert(get == -2); 85 | get = 0xfacade; 86 | vector_get_last(&get, me); 87 | assert(get == -2); 88 | vector_remove_first(me); 89 | vector_remove_at(me, 2); 90 | vector_remove_last(me); 91 | assert(vector_size(me) == 3); 92 | get = 345; 93 | vector_get_first(&get, me); 94 | assert(get == -1); 95 | vector_get_at(&get, me, 1); 96 | assert(get == 9); 97 | vector_get_last(&get, me); 98 | assert(get == 3); 99 | set = 12; 100 | vector_set_first(me, &set); 101 | set = 13; 102 | vector_set_at(me, 1, &set); 103 | set = 14; 104 | vector_set_last(me, &set); 105 | vector_copy_to_array(arr, me); 106 | assert(arr[0] == 12); 107 | assert(arr[1] == 13); 108 | assert(arr[2] == 14); 109 | set = -5; 110 | vector_set_at(me, 0, &set); 111 | set = -6; 112 | vector_set_at(me, 1, &set); 113 | set = -7; 114 | vector_set_at(me, 2, &set); 115 | vector_copy_to_array(arr, me); 116 | assert(arr[0] == -5); 117 | assert(arr[1] == -6); 118 | assert(arr[2] == -7); 119 | } 120 | 121 | static void test_invalid_operations(vector me) 122 | { 123 | int set; 124 | int i; 125 | assert(vector_reserve(me, 100) == 0); 126 | assert(vector_set_at(me, 4, &set) == -EINVAL); 127 | assert(vector_get_at(&set, me, 4) == -EINVAL); 128 | assert(vector_remove_at(me, 4) == -EINVAL); 129 | assert(vector_add_at(me, 5, &set) == -EINVAL); 130 | assert(vector_set_at(me, -1, &set) == -EINVAL); 131 | assert(vector_get_at(&set, me, -1) == -EINVAL); 132 | assert(vector_remove_at(me, -1) == -EINVAL); 133 | assert(vector_add_at(me, -1, &set) == -EINVAL); 134 | vector_clear(me); 135 | for (i = 0; i < 32; i++) { 136 | vector_add_last(me, &i); 137 | } 138 | vector_clear(me); 139 | assert(vector_capacity(me) == 8); 140 | assert(vector_size(me) == 0); 141 | assert(vector_is_empty(me)); 142 | assert(vector_remove_first(me) == -EINVAL); 143 | assert(vector_remove_last(me) == -EINVAL); 144 | } 145 | 146 | static void test_basic(void) 147 | { 148 | vector me = vector_init(sizeof(int)); 149 | assert(me); 150 | assert(vector_size(me) == 0); 151 | assert(vector_is_empty(me)); 152 | test_adding(me); 153 | test_trim(me); 154 | test_linear_operations(me); 155 | test_invalid_operations(me); 156 | assert(!vector_destroy(me)); 157 | } 158 | 159 | static void test_vector_of_vectors(void) 160 | { 161 | /* Test using a vector of vectors of ints. */ 162 | vector outer = vector_init(sizeof(vector)); 163 | /* Add vectors to the outer vector. */ 164 | int i; 165 | int j; 166 | for (i = 0; i < 5; i++) { 167 | vector inner = vector_init(sizeof(int)); 168 | for (j = 1; j <= 10; j++) { 169 | vector_add_last(inner, &j); 170 | } 171 | assert(vector_size(inner) == 10); 172 | vector_add_last(outer, &inner); 173 | } 174 | assert(vector_size(outer) == 5); 175 | /* Delete the vectors in the outer vector. */ 176 | for (i = 0; i < 5; i++) { 177 | vector inner = NULL; 178 | vector_get_first(&inner, outer); 179 | for (j = 0; j < 10; j++) { 180 | int num = 0xfacade; 181 | vector_get_at(&num, inner, j); 182 | assert(num == j + 1); 183 | } 184 | vector_remove_first(outer); 185 | vector_destroy(inner); 186 | } 187 | assert(vector_is_empty(outer)); 188 | vector_destroy(outer); 189 | } 190 | 191 | static void test_dynamic(void) 192 | { 193 | char **str = malloc(5 * sizeof(char **)); 194 | int i; 195 | int j; 196 | vector str_vector; 197 | for (i = 0; i < 5; i++) { 198 | str[i] = malloc(10 * sizeof(char *)); 199 | for (j = 0; j < 9; j++) { 200 | str[i][j] = (char) ('a' + i); 201 | } 202 | str[i][9] = '\0'; 203 | } 204 | str_vector = vector_init(sizeof(char *)); 205 | assert(str_vector); 206 | for (i = 0; i < 5; i++) { 207 | vector_add_last(str_vector, &str[i]); 208 | } 209 | assert(vector_size(str_vector) == 5); 210 | for (i = 0; i < 5; i++) { 211 | char *retrieve = NULL; 212 | vector_get_first(&retrieve, str_vector); 213 | vector_remove_first(str_vector); 214 | assert(strcmp(retrieve, str[i]) == 0); 215 | free(retrieve); 216 | } 217 | free(str); 218 | assert(vector_size(str_vector) == 0); 219 | assert(!vector_destroy(str_vector)); 220 | } 221 | 222 | static void test_reserve_erange(void) 223 | { 224 | const size_t max_size = -1; 225 | vector me = vector_init(sizeof(int)); 226 | assert(vector_reserve(me, max_size) == -ERANGE); 227 | vector_destroy(me); 228 | } 229 | 230 | #if STUB_MALLOC 231 | static void test_init_out_of_memory(void) 232 | { 233 | fail_malloc = 1; 234 | assert(!vector_init(sizeof(int))); 235 | fail_malloc = 1; 236 | delay_fail_malloc = 1; 237 | assert(!vector_init(sizeof(int))); 238 | } 239 | #endif 240 | 241 | #if STUB_MALLOC 242 | static void test_set_space_out_of_memory(void) 243 | { 244 | vector me = vector_init(sizeof(int)); 245 | int i; 246 | for (i = 0; i < 7; i++) { 247 | assert(vector_add_last(me, &i) == 0); 248 | } 249 | fail_realloc = 1; 250 | assert(vector_reserve(me, 9) == -ENOMEM); 251 | assert(vector_size(me) == 7); 252 | assert(vector_capacity(me) == 8); 253 | for (i = 0; i < 7; i++) { 254 | int get = 0xfacade; 255 | vector_get_at(&get, me, i); 256 | assert(get == i); 257 | } 258 | assert(!vector_destroy(me)); 259 | } 260 | #endif 261 | 262 | #if STUB_MALLOC 263 | static void test_add_out_of_memory(void) 264 | { 265 | vector me = vector_init(sizeof(int)); 266 | int i; 267 | for (i = 0; i < 8; i++) { 268 | assert(vector_add_last(me, &i) == 0); 269 | } 270 | i++; 271 | fail_realloc = 1; 272 | assert(vector_add_last(me, &i) == -ENOMEM); 273 | assert(vector_size(me) == 8); 274 | assert(vector_capacity(me) == 8); 275 | for (i = 0; i < 8; i++) { 276 | int get = 0xfacade; 277 | vector_get_at(&get, me, i); 278 | assert(get == i); 279 | } 280 | assert(!vector_destroy(me)); 281 | } 282 | #endif 283 | 284 | struct big_object { 285 | int n; 286 | double d; 287 | signed char c[8]; 288 | }; 289 | 290 | static void test_big_object(void) 291 | { 292 | int i; 293 | vector me = vector_init(sizeof(struct big_object)); 294 | assert(me); 295 | for (i = 0; i < 16; i++) { 296 | int j; 297 | struct big_object b; 298 | b.n = INT_MIN + i; 299 | b.d = i + 0.5; 300 | for (j = 0; j < 8; j++) { 301 | b.c[j] = (signed char) (SCHAR_MIN + i + j); 302 | } 303 | assert(vector_add_first(me, &b) == 0); 304 | b.n = -1; 305 | b.d = -1; 306 | for (j = 0; j < 8; j++) { 307 | b.c[j] = -1; 308 | } 309 | } 310 | for (i = 0; i < 16; i++) { 311 | int j; 312 | struct big_object b; 313 | assert(vector_get_last(&b, me) == 0); 314 | assert(vector_remove_last(me) == 0); 315 | assert(b.n == INT_MIN + i); 316 | assert(b.d == i + 0.5); 317 | for (j = 0; j < 8; j++) { 318 | assert(b.c[j] == SCHAR_MIN + i + j); 319 | } 320 | } 321 | assert(!vector_destroy(me)); 322 | } 323 | 324 | static void test_add_all(void) 325 | { 326 | size_t i; 327 | const size_t max_size = -1; 328 | double small_array[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 329 | vector me = vector_init(sizeof(double)); 330 | assert(vector_add_all(me, small_array, 10) == BK_OK); 331 | assert(vector_size(me) == 10); 332 | for (i = 0; i < 10; i++) { 333 | double get; 334 | assert(vector_get_at(&get, me, i) == BK_OK); 335 | assert(get == i + 1); 336 | } 337 | assert(vector_add_all(me, small_array, max_size) == -BK_ERANGE); 338 | assert(vector_add_all(me, small_array, max_size - 10) == -BK_ERANGE); 339 | assert(vector_add_all(me, small_array, max_size - 20) == -BK_ERANGE); 340 | vector_destroy(me); 341 | } 342 | 343 | void test_vector(void) 344 | { 345 | test_invalid_init(); 346 | test_basic(); 347 | test_vector_of_vectors(); 348 | test_dynamic(); 349 | test_reserve_erange(); 350 | #if STUB_MALLOC 351 | test_init_out_of_memory(); 352 | test_set_space_out_of_memory(); 353 | test_add_out_of_memory(); 354 | #endif 355 | test_big_object(); 356 | test_add_all(); 357 | vector_destroy(NULL); 358 | } 359 | --------------------------------------------------------------------------------