Basic structure for V2
This commit is contained in:
1 parent
9cadaeea85
commit
2c9759e5ec
213 files changed
+3305
-66141
No files matched your search
@@ -4,7 +4,7 @@
|
||||
<img src="https://leoven.github.io/C-Macro-Collections/img/logo.png" alt="C Macro Collections Logo" width="300"/>
|
||||
</p>
|
||||
|
||||
<p align="center">Easy to use, header only, macro generated, generic and type-safe Data Structures in C.</p>
|
||||
<p align="center">Easy to use, modular, header only, macro based, generic and type-safe Data Structures in C.</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/LeoVen/C-Macro-Collections"><img src="https://img.shields.io/badge/GitHub-C%20Macro%20Collections-2195F3.svg?logo=github" alt="LinkToRepo"/></a>
|
||||
@@ -39,7 +39,7 @@ No installation is required. The entire library is made of header files and can
|
||||
|
||||
## Contributing
|
||||
|
||||
There is a lot to be done. You can check the `TODO` file in the root of the repository or the issues in the github page. Also, tests and documentation are in constant development. Also check out the `STATUS` file for the status on the development of the library.
|
||||
There is a lot to be done. You can check the `TODO` file in the root of the repository or the issues in the github page. Also, tests and documentation are in constant development.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
Approximate completion of the library
|
||||
|
||||
[ 99 ][ 99 ][ 99 ] %
|
||||
[source][tests][docs]
|
||||
|
||||
## - Finished
|
||||
|
||||
[30][15][01] Library
|
||||
|
||||
[91][45][01] CMC
|
||||
[40][40][05] BitSet
|
||||
[##][##][10] Deque
|
||||
[80][70][00] HashBidiMap
|
||||
[##][##][00] HashMap
|
||||
[##][20][00] HashMultiMap
|
||||
[##][20][00] HashMultiSet
|
||||
[##][40][00] HashSet
|
||||
[##][30][00] Heap
|
||||
[##][40][00] IntervalHeap
|
||||
[90][20][00] LinkedList
|
||||
[90][30][00] List
|
||||
[##][60][00] Queue
|
||||
[00][00][00] SkipList
|
||||
[80][20][00] SortedList
|
||||
[95][90][00] Stack
|
||||
[00][00][00] TreeBidiMap
|
||||
[95][20][00] TreeMap
|
||||
[00][00][00] TreeMultiMap
|
||||
[00][00][00] TreeMultiSet
|
||||
[95][20][00] TreeSet
|
||||
[00][00][00] SAC
|
||||
[00][00][00] BitSet
|
||||
[00][00][00] Deque
|
||||
[00][00][00] HashBidiMap
|
||||
[00][00][00] HashMap
|
||||
[00][00][00] HashMultiMap
|
||||
[00][00][00] HashMultiSet
|
||||
[00][00][00] HashSet
|
||||
[00][00][00] Heap
|
||||
[00][00][00] IntervalHeap
|
||||
[00][00][00] LinkedList
|
||||
[00][00][00] List
|
||||
[00][00][00] Queue
|
||||
[00][00][00] SkipList
|
||||
[00][00][00] SortedList
|
||||
[00][00][00] Stack
|
||||
[00][00][00] TreeBidiMap
|
||||
[00][00][00] TreeMap
|
||||
[00][00][00] TreeMultiMap
|
||||
[00][00][00] TreeMultiSet
|
||||
[00][00][00] TreeSet
|
||||
[00][00][00] TSC
|
||||
[00][00][00] BitSet
|
||||
[00][00][00] Deque
|
||||
[00][00][00] HashBidiMap
|
||||
[00][00][00] HashMap
|
||||
[00][00][00] HashMultiMap
|
||||
[00][00][00] HashMultiSet
|
||||
[00][00][00] HashSet
|
||||
[00][00][00] Heap
|
||||
[00][00][00] IntervalHeap
|
||||
[00][00][00] LinkedList
|
||||
[00][00][00] List
|
||||
[00][00][00] Queue
|
||||
[00][00][00] SkipList
|
||||
[00][00][00] SortedList
|
||||
[00][00][00] Stack
|
||||
[00][00][00] TreeBidiMap
|
||||
[00][00][00] TreeMap
|
||||
[00][00][00] TreeMultiMap
|
||||
[00][00][00] TreeMultiSet
|
||||
[00][00][00] TreeSet
|
||||
-502
@@ -1,502 +0,0 @@
|
||||
# A script for automation
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from typing import List, Text
|
||||
|
||||
# Config Script Configuration
|
||||
# Directories Names for directories
|
||||
# Files Names for files
|
||||
# Compiler Compiler Configurations
|
||||
# Macro Expansion Configuration for the code expansion
|
||||
# Collections All collections
|
||||
#
|
||||
# Variables marked as const are to not be modified
|
||||
|
||||
# Directories
|
||||
|
||||
# Output directory
|
||||
# In this directory it is assumed that the following files and directories are
|
||||
# included: main.c, codecov.c, unt folder
|
||||
OUTPUT_DIR = './tests'
|
||||
# Where the unit test files are
|
||||
UNT_DIR = f'{OUTPUT_DIR}/unt'
|
||||
# Directory mapping
|
||||
DIR_MAP = {'HEADER': 'include', 'SOURCE': 'src'}
|
||||
# File extension mapping
|
||||
EXT_MAP = {'HEADER': 'h', 'SOURCE': 'c'}
|
||||
# Where compilation objects will be outputted
|
||||
BUILD_DIR = f'{OUTPUT_DIR}/build'
|
||||
# const
|
||||
INCLUDE_DIR = f"{OUTPUT_DIR}/{DIR_MAP['HEADER']}"
|
||||
# const
|
||||
SRC_DIR = f"{OUTPUT_DIR}/{DIR_MAP['SOURCE']}"
|
||||
# Where executables go
|
||||
BIN_DIR = f'{BUILD_DIR}/bin'
|
||||
# Where object files .o go
|
||||
OBJ_DIR = BUILD_DIR
|
||||
# Where .gcov files should go
|
||||
GCOV_DIR = f'{BUILD_DIR}/gcov'
|
||||
|
||||
# Files
|
||||
# All const
|
||||
|
||||
# The name of the main test
|
||||
MAIN = 'main'
|
||||
# The name of the code coverage file
|
||||
CODECOV = 'codecov'
|
||||
# The name of the single test file
|
||||
SINGLE = 'single'
|
||||
|
||||
# Compiler
|
||||
|
||||
# Compiler to be used
|
||||
CC = 'gcc'
|
||||
# Compilation Flags
|
||||
CFLAGS = ['-Wall', '-Werror', '-O3']
|
||||
# Link flags
|
||||
LFLAGS = []
|
||||
# Coverage Flags
|
||||
CVFLAGS = ['--coverage', '-O0']
|
||||
# gcov flags
|
||||
GCOV_FLAGS = []
|
||||
# Include of the main library
|
||||
# const
|
||||
INCLUDE = ['-I', './src']
|
||||
# Include to the test file headers
|
||||
# const
|
||||
TINCLUDE = ['-I', f'{INCLUDE_DIR}', '-I', f'{UNT_DIR}']
|
||||
# Include to code coverage
|
||||
# const
|
||||
CVINCLUDE = ['-I', INCLUDE_DIR, '-I', SRC_DIR, '-I', f'{UNT_DIR}']
|
||||
|
||||
# Macro Expansion
|
||||
|
||||
# -E Only preprocessor
|
||||
# -P No linemarkers
|
||||
# -C Keep comments, except those inside macros (for UNIQUE_FLAG)
|
||||
# const
|
||||
EXPAND_FLAGS = '-E -P -C'
|
||||
# Used to delimiter where the actual code starts and ends. Used by regex.
|
||||
# Needs to be a valid C comment.
|
||||
UNIQUE_FLAG = '// C_MACRO_COLLECTIONS_CODE'
|
||||
# Temporary file used to expand the macros
|
||||
TMP_FILE = './main.c'
|
||||
|
||||
|
||||
# All collections that can be used for testing
|
||||
COLLECTIONS = [
|
||||
# header, library, collection, pfx, sname, size, key, val
|
||||
{'h': '"cmc_bitset.h"', 'LIB': 'CMC', 'COLLECTION': 'BITSET', 'PFX': 'bs', 'SNAME': 'bitset', 'SIZE': '', 'K': '', 'V': '' },
|
||||
{'h': '"cmc_deque.h"', 'LIB': 'CMC', 'COLLECTION': 'DEQUE', 'PFX': 'd', 'SNAME': 'deque', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_hashbidimap.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHBIDIMAP', 'PFX': 'hbm', 'SNAME': 'hashbidimap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
|
||||
{'h': '"cmc_hashmap.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHMAP', 'PFX': 'hm', 'SNAME': 'hashmap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
|
||||
{'h': '"cmc_hashmultimap.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHMULTIMAP', 'PFX': 'hmm', 'SNAME': 'hashmultimap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
|
||||
{'h': '"cmc_hashmultiset.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHMULTISET', 'PFX': 'hms', 'SNAME': 'hashmultiset', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_hashset.h"', 'LIB': 'CMC', 'COLLECTION': 'HASHSET', 'PFX': 'hs', 'SNAME': 'hashset', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_heap.h"', 'LIB': 'CMC', 'COLLECTION': 'HEAP', 'PFX': 'h', 'SNAME': 'heap', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_intervalheap.h"', 'LIB': 'CMC', 'COLLECTION': 'INTERVALHEAP', 'PFX': 'ih', 'SNAME': 'intervalheap', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_linkedlist.h"', 'LIB': 'CMC', 'COLLECTION': 'LINKEDLIST', 'PFX': 'll', 'SNAME': 'linkedlist', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_list.h"', 'LIB': 'CMC', 'COLLECTION': 'LIST', 'PFX': 'l', 'SNAME': 'list', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_queue.h"', 'LIB': 'CMC', 'COLLECTION': 'QUEUE', 'PFX': 'q', 'SNAME': 'queue', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_sortedlist.h"', 'LIB': 'CMC', 'COLLECTION': 'SORTEDLIST', 'PFX': 'sl', 'SNAME': 'sortedlist', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_stack.h"', 'LIB': 'CMC', 'COLLECTION': 'STACK', 'PFX': 's', 'SNAME': 'stack', 'SIZE': '', 'K': '', 'V': 'size_t'},
|
||||
{'h': '"cmc_treemap.h"', 'LIB': 'CMC', 'COLLECTION': 'TREEMAP', 'PFX': 'tm', 'SNAME': 'treemap', 'SIZE': '', 'K': 'size_t', 'V': 'size_t'},
|
||||
{'h': '"cmc_treeset.h"', 'LIB': 'CMC', 'COLLECTION': 'TREESET', 'PFX': 'ts', 'SNAME': 'treeset', 'SIZE': '', 'K': '', 'V': 'size_t'}
|
||||
]
|
||||
|
||||
|
||||
# Just a realy helpfull overview
|
||||
CONFIG = f'''Directory Settings
|
||||
OUTPUT_DIR = {OUTPUT_DIR}
|
||||
UNT_DIR = {UNT_DIR}
|
||||
DIR_MAP = {DIR_MAP}
|
||||
EXT_MAP = {EXT_MAP}
|
||||
BUILD_DIR = {BUILD_DIR}
|
||||
INCLUDE_DIR = {INCLUDE_DIR}
|
||||
SRC_DIR = {SRC_DIR}
|
||||
OBJ_DIR = {OBJ_DIR}
|
||||
GCOV_DIR = {GCOV_DIR}
|
||||
File Settings
|
||||
MAIN = {MAIN}
|
||||
CODECOV = {CODECOV}
|
||||
SINGLE = {SINGLE}
|
||||
Compiler Settings
|
||||
CC = {CC}
|
||||
CFLAGS = {CFLAGS}
|
||||
LFLAGS = {LFLAGS}
|
||||
CVFLAGS = {CVFLAGS}
|
||||
GCOV_FLAGS = {GCOV_FLAGS}
|
||||
INCLUDE = {INCLUDE}
|
||||
TINCLUDE = {TINCLUDE}
|
||||
CVINCLUDE = {CVINCLUDE}
|
||||
Macro Expansion
|
||||
EXPAND_FLAGS = {EXPAND_FLAGS}
|
||||
UNIQUE_FLAG = {UNIQUE_FLAG}
|
||||
TMP_FILE = {TMP_FILE}'''
|
||||
|
||||
|
||||
def full_path(path: Text) -> Text:
|
||||
'''
|
||||
Returns the full path of a 'path' with ralative paths, e.g. './' or '../'
|
||||
'''
|
||||
return str(pathlib.Path(path).resolve())
|
||||
|
||||
|
||||
def execute_command(commands: List[Text]):
|
||||
cmd = ' '.join(commands)
|
||||
print(cmd)
|
||||
subprocess.check_call(cmd, shell=True)
|
||||
|
||||
# if cp.returncode != 0:
|
||||
# print('Error when executing the last command')
|
||||
# exit(1)
|
||||
|
||||
|
||||
def require_executable(program: Text):
|
||||
'''
|
||||
Asserts that a given program is installed and available in PATH. Raises an exception if it doesn't.
|
||||
'''
|
||||
if shutil.which(program) is None:
|
||||
raise Exception(f'The required executable {program} was not found in your path')
|
||||
|
||||
|
||||
def require_file(file: Text):
|
||||
'''
|
||||
Asserts that a given file exists. Raises an exception if it doesn't.
|
||||
'''
|
||||
f = pathlib.Path(file).resolve()
|
||||
if not f.is_file():
|
||||
raise Exception(f'The required file {str(f)} was not found')
|
||||
|
||||
|
||||
def assert_dir(directory: Text):
|
||||
'''
|
||||
Given a string 'directory' that is a path to a directory, make sure that it exists.
|
||||
'''
|
||||
# TODO change this to use pathlib ?
|
||||
if not os.path.exists(directory):
|
||||
os.makedirs(directory)
|
||||
|
||||
|
||||
def assert_structure():
|
||||
'''
|
||||
Git might not commit some required directories. This function asserts that they exist.
|
||||
'''
|
||||
assert_dir(OUTPUT_DIR)
|
||||
|
||||
# include and src
|
||||
for directory in DIR_MAP.values():
|
||||
assert_dir(f'{OUTPUT_DIR}/{directory}')
|
||||
|
||||
assert_dir(BUILD_DIR)
|
||||
assert_dir(OBJ_DIR)
|
||||
assert_dir(BIN_DIR)
|
||||
assert_dir(GCOV_DIR)
|
||||
|
||||
|
||||
def format_code(source: bool, tests: bool):
|
||||
'''
|
||||
Format all source files from the main library or test files.
|
||||
'''
|
||||
if source:
|
||||
execute_command(['find', './src/', '-name', '*.h', '|', 'xargs', 'clang-format', '--style=file', '--verbose', '-i'])
|
||||
if tests:
|
||||
execute_command(['find', './tests/', '-name', '*.c', '-o', '-name', '*.h', '|', 'xargs', 'clang-format', '--style=file', '--verbose', '-i'])
|
||||
|
||||
|
||||
def clean_build(cleanfull: bool):
|
||||
'''
|
||||
Removes all files generated by compilation and code coverage along with folders.
|
||||
'''
|
||||
# -f prevents 'rm' from failing
|
||||
execute_command(['rm', '-r', '-f', f'./*.gcov'])
|
||||
execute_command(['rm', '-r', '-f', f'{OUTPUT_DIR}/*.exe'])
|
||||
execute_command(['rm', '-r', '-f', BUILD_DIR])
|
||||
execute_command(['rm', '-f', './*.gcda'])
|
||||
execute_command(['rm', '-f', './*.gcno'])
|
||||
|
||||
if cleanfull:
|
||||
execute_command(['rm', '-r', SRC_DIR])
|
||||
execute_command(['rm', '-r', INCLUDE_DIR])
|
||||
|
||||
|
||||
def expand_code():
|
||||
'''
|
||||
Expands code to be used in tests. This is necessary because code coverage doesn't work with macros.
|
||||
'''
|
||||
# Generate Header and Source separately
|
||||
for ftype in ['HEADER', 'SOURCE']:
|
||||
for data in COLLECTIONS:
|
||||
file = open(TMP_FILE, 'w')
|
||||
|
||||
file.write(
|
||||
f'''
|
||||
#include "macro_collections.h"
|
||||
|
||||
{UNIQUE_FLAG}
|
||||
|
||||
C_MACRO_COLLECTIONS_ALL_{ftype}({data['LIB']}, {data['COLLECTION']}, PUBLIC, ({', '.join([data['PFX'], data['SNAME'], data['SIZE'], data['K'], data['V']])}))
|
||||
|
||||
{UNIQUE_FLAG}
|
||||
''')
|
||||
|
||||
file.flush()
|
||||
file.close()
|
||||
|
||||
result = subprocess.getoutput(f'{CC} {EXPAND_FLAGS} {" ".join(INCLUDE)} {TMP_FILE}')
|
||||
|
||||
# (?s) makes '.' match anything, even '\n'
|
||||
match = re.search(fr'(?s){UNIQUE_FLAG}(?P<code>.+){UNIQUE_FLAG}', result)
|
||||
|
||||
if match is None:
|
||||
os.remove(TMP_FILE)
|
||||
print('Didn\'t match FLAG. Probably because compilation failed.', file=sys.stderr)
|
||||
exit(1)
|
||||
|
||||
file = open(f'{OUTPUT_DIR}/{DIR_MAP[ftype]}/tst_{data["LIB"].lower()}_{data["SNAME"]}.{EXT_MAP[ftype]}', 'w')
|
||||
|
||||
if ftype == 'HEADER':
|
||||
file.write(
|
||||
f'''
|
||||
#ifndef CMC_{data['LIB']}_{data['COLLECTION']}_TEST_H
|
||||
#define CMC_{data['LIB']}_{data['COLLECTION']}_TEST_H
|
||||
|
||||
#include "macro_collections.h"
|
||||
{match.group('code')}
|
||||
|
||||
#endif /* CMC_{data['LIB']}_{data['COLLECTION']}_TEST_H */
|
||||
''')
|
||||
else:
|
||||
file.write(
|
||||
f'''
|
||||
#include {'"tst_' + data["h"][1:]}
|
||||
|
||||
{match.group("code")}
|
||||
''')
|
||||
|
||||
file.flush()
|
||||
file.close()
|
||||
|
||||
print(f'''Generated {'"tst_' + data["h"][1:]: >24} -> {OUTPUT_DIR}/{DIR_MAP[ftype]}/tst_{data["LIB"].lower()}_{data["SNAME"]}.{EXT_MAP[ftype]}''')
|
||||
|
||||
os.remove(TMP_FILE)
|
||||
|
||||
|
||||
def format_expand():
|
||||
'''
|
||||
Format the files outputted by 'expand_code'.
|
||||
'''
|
||||
cmd = ['clang-format', '--style=file', '--verbose', '-i']
|
||||
dirs_to_format = [f'{OUTPUT_DIR}/{DIR_MAP[ftype]}/*.{EXT_MAP[ftype]}' for ftype in DIR_MAP.keys()]
|
||||
cmd.extend(dirs_to_format)
|
||||
execute_command(cmd)
|
||||
|
||||
|
||||
def build_main():
|
||||
'''
|
||||
Build all object files and main.c for tests.
|
||||
'''
|
||||
for data in COLLECTIONS:
|
||||
cmd = [CC]
|
||||
cmd += TINCLUDE # This one needs to go first
|
||||
cmd += INCLUDE
|
||||
cmd += ['-c', f"{SRC_DIR}/tst_{data['LIB'].lower()}_{data['SNAME']}.c"]
|
||||
cmd += ['-o', f"{OBJ_DIR}/tst_{data['LIB'].lower()}_{data['SNAME']}.o"]
|
||||
execute_command(cmd)
|
||||
|
||||
# Build OUTPUT_DIR/main.c
|
||||
cmd = [CC]
|
||||
cmd += TINCLUDE # This one needs to go first
|
||||
cmd += INCLUDE
|
||||
cmd += ['-c', f'{OUTPUT_DIR}/{MAIN}.c']
|
||||
cmd += ['-o', f'{OBJ_DIR}/{MAIN}.o']
|
||||
execute_command(cmd)
|
||||
|
||||
# Link everything producing OUTPUT_DIR/main.exe
|
||||
cmd = [CC]
|
||||
cmd += LFLAGS
|
||||
cmd += ['-o', f'{BIN_DIR}/{MAIN}.exe']
|
||||
cmd += [f'{OBJ_DIR}/main.o']
|
||||
cmd += [f'{OBJ_DIR}/tst_{data["LIB"].lower()}_{data["SNAME"]}.o' for data in COLLECTIONS]
|
||||
execute_command(cmd)
|
||||
|
||||
|
||||
def run_main():
|
||||
'''
|
||||
Runs main.exe
|
||||
'''
|
||||
execute_command([full_path(f'{BIN_DIR}/{MAIN}.exe')])
|
||||
|
||||
|
||||
def build_codecov():
|
||||
'''
|
||||
Builds codecov.c for code coverage.
|
||||
'''
|
||||
cmd = [CC]
|
||||
cmd += CVFLAGS
|
||||
cmd += CVINCLUDE # This one needs to go first
|
||||
cmd += INCLUDE
|
||||
cmd += [f'{OUTPUT_DIR}/{CODECOV}.c']
|
||||
cmd += ['-o', f'{BIN_DIR}/{CODECOV}.exe']
|
||||
execute_command(cmd)
|
||||
|
||||
|
||||
def run_codecov():
|
||||
'''
|
||||
Runs codecov.exe and then gcov on the generated gcda files. All gcov files then go to GCOV_DIR.
|
||||
'''
|
||||
execute_command([full_path(f'{BIN_DIR}/{CODECOV}.exe')])
|
||||
execute_command(['gcov'] + GCOV_FLAGS + [f'{CODECOV}.gcda'])
|
||||
execute_command(['rm', '*.h.gcov'])
|
||||
|
||||
|
||||
def tidy():
|
||||
'''
|
||||
Places files to their respective directory.
|
||||
'''
|
||||
execute_command(['mv', '*.gcov', GCOV_DIR])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
p = argparse.ArgumentParser('autogen.py', usage='%(prog)s [options]')
|
||||
|
||||
p.add_argument('-sc', '--show-config',
|
||||
help='Displays the current configuration',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='config')
|
||||
|
||||
source = p.add_argument_group('source', 'For dealing with the source files and formatting')
|
||||
|
||||
expand = p.add_argument_group('expand', 'For dealing with code generation and formatting for tests')
|
||||
|
||||
task = p.add_argument_group('task', 'Specify a task (mutually exclusive)')
|
||||
task_ = task.add_mutually_exclusive_group()
|
||||
|
||||
action = p.add_argument_group('action', 'Actions on task')
|
||||
|
||||
task_.add_argument('-cv', '--codecov',
|
||||
help='Designates task as code coverage (uses codecov.c)',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='codecov')
|
||||
task_.add_argument('-m', '--main',
|
||||
help='Designates task as the main tests (uses main.c)',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='main')
|
||||
task_.add_argument('-s', '--single',
|
||||
help='Designates task as an individual test (uses single.c)',
|
||||
dest='single')
|
||||
|
||||
expand.add_argument('-c', '--clean',
|
||||
help='Cleans all build objects',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='clean')
|
||||
expand.add_argument('-cf', '--clean-full',
|
||||
help='Cleans all build objects, source and header files, and removes folders',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='cleanfull')
|
||||
expand.add_argument('-e', '--expand',
|
||||
help='Expands the header and source files',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='expand')
|
||||
expand.add_argument('-nf', '--no-format',
|
||||
help='Does not format the output of expand. Can be used when you might not have clang-format',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='noformat')
|
||||
expand.add_argument('-nt', '--no-tidy',
|
||||
help='Don\'t move files around',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='notidy')
|
||||
|
||||
action.add_argument('-b', '--build',
|
||||
help='Build task',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='build')
|
||||
action.add_argument('-r', '--run',
|
||||
help='Run task',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='run')
|
||||
|
||||
source.add_argument('-fs', '--format-source',
|
||||
help='Format the source code',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='fmt_source')
|
||||
source.add_argument('-ft', '--format-tests',
|
||||
help='Format tests files',
|
||||
default=False,
|
||||
action='store_true',
|
||||
dest='fmt_tests')
|
||||
|
||||
args = p.parse_args()
|
||||
|
||||
has_target = args.main or args.codecov or args.single
|
||||
|
||||
if args.config:
|
||||
print(CONFIG)
|
||||
exit(0)
|
||||
|
||||
if args.fmt_source or args.fmt_tests:
|
||||
require_executable('find')
|
||||
require_executable('xargs')
|
||||
format_code(args.fmt_source, args.fmt_tests)
|
||||
# Prevent mixing code
|
||||
exit(0)
|
||||
|
||||
if not args.cleanfull:
|
||||
assert_structure()
|
||||
if args.clean:
|
||||
clean_build(False)
|
||||
else:
|
||||
clean_build(True)
|
||||
# Nothing else will work, so just exit
|
||||
exit(0)
|
||||
|
||||
if args.expand:
|
||||
expand_code()
|
||||
if not args.noformat:
|
||||
require_executable('clang-format')
|
||||
format_expand()
|
||||
else:
|
||||
# In case the next task is to build the code from source
|
||||
# This warning is a very annoying one from gcc
|
||||
CFLAGS += ['-Wno-misleading-indentation']
|
||||
|
||||
if args.build:
|
||||
require_executable(CC)
|
||||
if args.codecov:
|
||||
require_executable('gcov')
|
||||
|
||||
if args.codecov:
|
||||
require_file(f'{OUTPUT_DIR}/{CODECOV}.c')
|
||||
if args.build:
|
||||
build_codecov()
|
||||
if args.run:
|
||||
run_codecov()
|
||||
elif args.main:
|
||||
require_file(f'{OUTPUT_DIR}/{MAIN}.c')
|
||||
if args.build:
|
||||
build_main()
|
||||
if args.run:
|
||||
run_main()
|
||||
elif args.single:
|
||||
require_file(f'{OUTPUT_DIR}/{SINGLE}.c')
|
||||
# TODO
|
||||
|
||||
if not args.notidy and args.codecov:
|
||||
tidy()
|
||||
@@ -1,62 +0,0 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
CMC_CMC_HASHMAP_CORE(PUBLIC, HEADER, (hm, hashmap, , uint64_t, uint64_t))
|
||||
CMC_CMC_HASHMAP_CORE(PUBLIC, SOURCE, (hm, hashmap, , uint64_t, uint64_t))
|
||||
|
||||
int cmp(uint64_t a, uint64_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// size_t hash(uint64_t a)
|
||||
// {
|
||||
// size_t x = (size_t)a;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = (x >> 16) ^ x;
|
||||
// return x;
|
||||
// }
|
||||
|
||||
size_t hash(uint64_t k)
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
|
||||
struct hashmap_fkey *fkey = &(struct hashmap_fkey) {
|
||||
.cmp = cmp,
|
||||
.hash = hash,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct hashmap_fval *fval = &(struct hashmap_fval) {
|
||||
.cmp = cmp,
|
||||
.hash = hash,
|
||||
NULL
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
struct hashmap *map = hm_new(COUNT, 0.6, fkey, fval);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
hm_insert(map, v, v);
|
||||
}
|
||||
|
||||
hm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
CMC_CMC_HASHMULTIMAP_CORE(PUBLIC, HEADER, (hmm, hashmultimap, , uint64_t, uint64_t))
|
||||
CMC_CMC_HASHMULTIMAP_CORE(PUBLIC, SOURCE, (hmm, hashmultimap, , uint64_t, uint64_t))
|
||||
|
||||
int cmp(uint64_t a, uint64_t b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// size_t hash(uint64_t a)
|
||||
// {
|
||||
// size_t x = (size_t)a;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
// x = (x >> 16) ^ x;
|
||||
// return x;
|
||||
// }
|
||||
|
||||
size_t hash(uint64_t k)
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
|
||||
struct hashmultimap_fkey *fkey = &(struct hashmultimap_fkey) {
|
||||
.cmp = cmp,
|
||||
.hash = hash,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct hashmultimap_fval *fval = &(struct hashmultimap_fval) {
|
||||
.cmp = cmp,
|
||||
.hash = hash,
|
||||
NULL
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
struct hashmultimap *map = hmm_new(COUNT, 0.6, fkey, fval);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
hmm_insert(map, v, v);
|
||||
}
|
||||
|
||||
hmm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/hash_bytes.cc
|
||||
|
||||
#ifndef MURMURHASH
|
||||
#define MURMURHASH
|
||||
|
||||
#include <string.h>
|
||||
|
||||
inline size_t unaligned_load(const char *p)
|
||||
{
|
||||
size_t result;
|
||||
memcpy(&result, p, sizeof(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t load_bytes(const char *p, int n)
|
||||
{
|
||||
size_t result = 0;
|
||||
--n;
|
||||
do
|
||||
{
|
||||
result = (result << 8) + (unsigned char)(p[n]);
|
||||
} while (--n >= 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
inline size_t shift_mix(size_t v)
|
||||
{
|
||||
return v ^ (v >> 47);
|
||||
}
|
||||
|
||||
size_t MurMurHash(const void *ptr, size_t len, size_t seed)
|
||||
{
|
||||
static const size_t mul = (((size_t)0xc6a4a793UL) << 32UL) + (size_t)0x5bd1e995UL;
|
||||
const char *const buf = (const char *)(ptr);
|
||||
|
||||
// Remove the bytes not divisible by the sizeof(size_t). This
|
||||
// allows the main loop to process the data as 64-bit integers.
|
||||
const size_t len_aligned = len & ~(size_t)0x7;
|
||||
const char *const end = buf + len_aligned;
|
||||
size_t hash = seed ^ (len * mul);
|
||||
for (const char *p = buf; p != end; p += 8)
|
||||
{
|
||||
const size_t data = shift_mix(unaligned_load(p) * mul) * mul;
|
||||
hash ^= data;
|
||||
hash *= mul;
|
||||
}
|
||||
if ((len & 0x7) != 0)
|
||||
{
|
||||
const size_t data = load_bytes(end, len & 0x7);
|
||||
hash ^= data;
|
||||
hash *= mul;
|
||||
}
|
||||
hash = shift_mix(hash) * mul;
|
||||
hash = shift_mix(hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
#endif /* MURMURHASH */
|
||||
@@ -1,57 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
ITERATIONS = 10
|
||||
COUNT = 20000000
|
||||
VERBOSE = False
|
||||
|
||||
NL = '\n'
|
||||
|
||||
INCLUDE = "../../../src"
|
||||
CC = 'gcc'
|
||||
CCPP = 'g++' # LoL
|
||||
OPT = '-O3'
|
||||
|
||||
print(f'Using {CC} compiler')
|
||||
|
||||
|
||||
def execute_command(commands):
|
||||
print(' '.join(commands))
|
||||
subprocess.run(commands, shell=True)
|
||||
|
||||
|
||||
# Common args
|
||||
args = ['-I', INCLUDE, OPT, f'-DCOUNT={COUNT}', '-DCMC_NO_CALLBACKS']
|
||||
|
||||
map_args = [CC, 'hashmap.c', '-o', 'hashmap.exe']
|
||||
mmap_args = [CC, 'hashmultimap.c', '-o', 'hashmultimap.exe']
|
||||
cpp_args = [CCPP, 'unorderedmap.cpp', '-I', INCLUDE, '-o', 'unorderedmap.exe', OPT, f'-DCOUNT={COUNT}']
|
||||
|
||||
map_args.extend(args)
|
||||
mmap_args.extend(args)
|
||||
cpp_args.extend(args)
|
||||
|
||||
execute_command(map_args)
|
||||
execute_command(mmap_args)
|
||||
execute_command(cpp_args)
|
||||
|
||||
programs = ['hashmap.exe', 'hashmultimap.exe', 'unorderedmap.exe']
|
||||
|
||||
for prog in programs:
|
||||
total = 0
|
||||
for i in range(ITERATIONS):
|
||||
print(f'{i}...', end='')
|
||||
sys.stdout.flush()
|
||||
start_time = time.time()
|
||||
subprocess.run(prog, shell=True)
|
||||
|
||||
delta = time.time() - start_time
|
||||
total += delta
|
||||
|
||||
if VERBOSE:
|
||||
print(f'({delta})')
|
||||
|
||||
avg = total / ITERATIONS
|
||||
print(f'{"" if VERBOSE else NL}{avg} seconds for {COUNT} -> AVG[{int((avg * 1e9) / COUNT)} ns] [{prog}]{NL if VERBOSE else ""}')
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef COUNT
|
||||
#error "Please define COUNT"
|
||||
#endif
|
||||
|
||||
#include "murmurhash.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../../util/twister.c"
|
||||
|
||||
struct IntHasher
|
||||
{
|
||||
std::size_t operator()(const uint64_t& k) const
|
||||
{
|
||||
static size_t seed = 211106232532969;
|
||||
return MurMurHash(&k, sizeof(k), seed);
|
||||
}
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
mt_state tw;
|
||||
twist_init(&tw, 50331653);
|
||||
|
||||
std::unordered_map<uint64_t, uint64_t, IntHasher> map(COUNT);
|
||||
|
||||
for (uint64_t i = 0; i < COUNT; i++)
|
||||
{
|
||||
uint64_t v = twist_uint64(&tw);
|
||||
map.insert({v, v});
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
/**
|
||||
* benchmark.c
|
||||
*
|
||||
* Creation Date: 13/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Benchmarks:
|
||||
* - Input
|
||||
* - Search
|
||||
* - Iteration
|
||||
* - Output
|
||||
*/
|
||||
#include "macro_collections.h"
|
||||
#include "util/twister.c"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define NTOTAL UINT64_C(10000000)
|
||||
#define NMIN UINT64_C(100)
|
||||
|
||||
// Percentage % macro
|
||||
#define PC(x) x * 100.0
|
||||
|
||||
static int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
size_t randsize(size_t min, size_t max, mt_state_ptr st)
|
||||
{
|
||||
return (size_t)floor(twist_real(st) * ((double)max - (double)min + 1.0) + (double)min);
|
||||
}
|
||||
|
||||
void shuffle(int *array, mt_state_ptr st)
|
||||
{
|
||||
for (size_t i = 0; i < NTOTAL; i++)
|
||||
{
|
||||
size_t j = randsize(0, NTOTAL - 1, st);
|
||||
int tmp = array[j];
|
||||
array[j] = array[i];
|
||||
array[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d, deque, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm, hmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs, hset, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h, heap, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll, linked, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l, list, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q, queue, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s, stack, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm, tmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts, tset, /* K */, int)
|
||||
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih, iheap, /* k */, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms, mset, /* K */, int)
|
||||
|
||||
#define BENCHMARK(NAME, PFX, sname, initfunc, insertbody, removebody, searchbody) \
|
||||
void NAME##_io_benchmark(int *array, int *sarray, size_t s) \
|
||||
{ \
|
||||
printf("+------------------------------------------------------------ %10s\n", #NAME); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
struct cmc_timer timer, total; \
|
||||
int r, k, v; \
|
||||
size_t j; \
|
||||
\
|
||||
struct sname *coll = initfunc; \
|
||||
\
|
||||
cmc_timer_start(total); \
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
insertbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
size_t s1 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" INPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double input_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < s; i++) \
|
||||
{ \
|
||||
searchbody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
printf(" SEARCH %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s); \
|
||||
\
|
||||
double search_time = timer.result; \
|
||||
\
|
||||
struct sname##_iter iter; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (PFX##_iter_init(&iter, coll); !PFX##_iter_end(&iter); PFX##_iter_next(&iter)) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
printf("ITERATION %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double iter_time = timer.result; \
|
||||
\
|
||||
cmc_timer_start(timer); \
|
||||
\
|
||||
for (size_t i = 0; i < NTOTAL; i++) \
|
||||
{ \
|
||||
removebody; \
|
||||
} \
|
||||
\
|
||||
cmc_timer_stop(timer); \
|
||||
\
|
||||
cmc_timer_calc(timer); \
|
||||
\
|
||||
size_t s2 = PFX##_count(coll); \
|
||||
\
|
||||
printf(" OUTPUT %10s TOOK %8.0lf milliseconds for %8" PRIuMAX " elements\n", #NAME, timer.result, s1); \
|
||||
\
|
||||
double output_time = timer.result; \
|
||||
\
|
||||
cmc_timer_stop(total); \
|
||||
cmc_timer_calc(total); \
|
||||
\
|
||||
PFX##_free(coll, NULL); \
|
||||
\
|
||||
double adj_search_time = (total.result - search_time) + (search_time * (double)NTOTAL) / (double)s; \
|
||||
double no_search = input_time + iter_time + output_time; \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf("TOTAL TIME : %.0lf milliseconds\n", total.result); \
|
||||
printf("ADJUSTED TIME : %.0lf milliseconds\n", adj_search_time); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
printf(" INPUT : %5.2lf%% (%5.2f%%)\n", PC(input_time / total.result), PC(input_time / no_search)); \
|
||||
printf(" SEARCH : %5.2lf%%\n", PC(search_time / total.result)); \
|
||||
printf("ITERATION : %5.2lf%% (%5.2f%%)\n", PC(iter_time / total.result), PC(iter_time / no_search)); \
|
||||
printf(" OUTPUT : %5.2lf%% (%5.2f%%)\n", PC(output_time / total.result), PC(output_time / no_search)); \
|
||||
printf("+------------------------------------------------------------ \n"); \
|
||||
\
|
||||
assert(s1 == NTOTAL && s2 == 0); \
|
||||
\
|
||||
printf("+------------------------------------------------------------ %10s\n\n", #NAME); \
|
||||
}
|
||||
|
||||
BENCHMARK(DEQUE, d, deque, d_new(NTOTAL), d_push_back(coll, array[i]), d_pop_back(coll), d_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(HASHMAP, hm, hmap, hm_new(NTOTAL, 0.6, intcmp, inthash), hm_insert(coll, array[i], array[i]), hm_remove(coll, array[i], &r), hm_contains(coll, sarray[i]))
|
||||
BENCHMARK(HASHSET, hs, hset, hs_new(NTOTAL, 0.6, intcmp, inthash), hs_insert(coll, array[i]), hs_remove(coll, array[i]), hs_contains(coll, sarray[i]))
|
||||
BENCHMARK(HEAP, h, heap, h_new(NTOTAL, cmc_min_heap, intcmp), h_insert(coll, array[i]), h_remove(coll, &r), h_contains(coll, sarray[i]))
|
||||
BENCHMARK(LINKEDLIST, ll, linked, ll_new(), ll_push_back(coll, array[i]), ll_pop_back(coll), ll_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(LIST, l, list, l_new(NTOTAL), l_push_back(coll, array[i]), l_pop_back(coll), l_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(QUEUE, q, queue, q_new(NTOTAL), q_enqueue(coll, array[i]), q_dequeue(coll), q_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(STACK, s, stack, s_new(NTOTAL), s_push(coll, array[i]), s_pop(coll), s_contains(coll, sarray[i], intcmp))
|
||||
BENCHMARK(TREEMAP, tm, tmap, tm_new(intcmp), tm_insert(coll, array[i], array[i]), tm_remove(coll, array[i], &r), tm_contains(coll, sarray[i]))
|
||||
BENCHMARK(TREESET, ts, tset, ts_new(intcmp), ts_insert(coll, array[i]), ts_remove(coll, array[i]), ts_contains(coll, sarray[i]))
|
||||
|
||||
BENCHMARK(INTERVALHEAP, ih, iheap, ih_new(NTOTAL, intcmp), ih_insert(coll, array[i]), ih_remove_max(coll, &r), ih_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTIMAP, mm, mmap, mm_new(NTOTAL, 0.8, intcmp, inthash), mm_insert(coll, array[i], array[i]), mm_remove(coll, array[i], &r), mm_contains(coll, sarray[i]))
|
||||
BENCHMARK(MULTISET, ms, mset, ms_new(NTOTAL, 0.6, intcmp, inthash), ms_insert(coll, array[i]), ms_remove(coll, array[i]), ms_contains(coll, sarray[i]))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Using the Mersenne Twister to generate random numbers. This seed
|
||||
// guarantees that everytime this program runs it will generate the same
|
||||
// random numbers. The random numbers influence on the shuffling of the
|
||||
// array.
|
||||
mt_state st;
|
||||
twist_init(&st, UINT64_C(12604951237));
|
||||
|
||||
int *array = malloc(NTOTAL * sizeof(int));
|
||||
int *sarray = malloc(NTOTAL * sizeof(int));
|
||||
|
||||
if (!array)
|
||||
{
|
||||
printf("Allocation failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (int i = -5000000; i < 5000000; i++)
|
||||
array[i + 5000000] = i;
|
||||
|
||||
shuffle(array, &st);
|
||||
|
||||
memcpy(sarray, array, NTOTAL * sizeof(int));
|
||||
|
||||
shuffle(sarray, &st);
|
||||
|
||||
printf("\nNote: Adjusted Time refers to if the container had done a search over all %" PRIuMAX " elements.\n\n", NTOTAL);
|
||||
|
||||
// Linear containers have to search for NMIN elements and non-linear (hash
|
||||
// and tree) have to search for all elements.
|
||||
struct cmc_timer timer;
|
||||
cmc_timer_start(timer);
|
||||
|
||||
DEQUE_io_benchmark(array, sarray, NMIN);
|
||||
HASHMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
HASHSET_io_benchmark(array, sarray, NTOTAL);
|
||||
HEAP_io_benchmark(array, sarray, NMIN);
|
||||
LINKEDLIST_io_benchmark(array, sarray, NMIN);
|
||||
LIST_io_benchmark(array, sarray, NMIN);
|
||||
QUEUE_io_benchmark(array, sarray, NMIN);
|
||||
STACK_io_benchmark(array, sarray, NMIN);
|
||||
TREEMAP_io_benchmark(array, sarray, NTOTAL);
|
||||
TREESET_io_benchmark(array, sarray, NTOTAL);
|
||||
|
||||
INTERVALHEAP_io_benchmark(array, array, NMIN);
|
||||
MULTIMAP_io_benchmark(array, array, NTOTAL);
|
||||
MULTISET_io_benchmark(array, array, NTOTAL);
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
cmc_timer_calc(timer);
|
||||
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
printf("| Total Benchmark Running Time : %12.0lf seconds | \n", timer.result / 1000);
|
||||
printf("+-----------------------------------------------------------+ \n");
|
||||
|
||||
free(array);
|
||||
free(sarray);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
main:
|
||||
gcc compile_time.c -c -O3 -ftime-report -I ../../src
|
||||
@@ -1,178 +0,0 @@
|
||||
/* Compilation time for over 90 collections */
|
||||
#include <macro_collections.h>
|
||||
|
||||
struct imaginary
|
||||
{
|
||||
double real;
|
||||
double imag;
|
||||
};
|
||||
|
||||
enum app_state
|
||||
{
|
||||
TRACE = 1,
|
||||
DEBUG = 2,
|
||||
INFO = 3,
|
||||
WARN = 4,
|
||||
ERROR = 5,
|
||||
FATAL = 6
|
||||
};
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd0, bidimap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d0, deque0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm0, hmap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs0, hset0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h0, heap0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih0, iheap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll0, linked0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(LIST, l0, list0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm0, mmap0, struct imaginary, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms0, mset0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(STACK, s0, stack0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl0, sotredlist0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q0, queue0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts0, tset0, /* K */, struct imaginary)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm0, tmap0, struct imaginary, struct imaginary)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd1, bidimap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d1, deque1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm1, hmap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs1, hset1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h1, heap1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih1, iheap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll1, linked1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(LIST, l1, list1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm1, mmap1, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms1, mset1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(STACK, s1, stack1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl1, sotredlist1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q1, queue1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts1, tset1, /* K */, int)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm1, tmap1, int, int)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd2, bidimap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d2, deque2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm2, hmap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs2, hset2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h2, heap2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih2, iheap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll2, linked2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(LIST, l2, list2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm2, mmap2, double, double)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms2, mset2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(STACK, s2, stack2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl2, sotredlist2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q2, queue2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts2, tset2, /* K */, double)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm2, tmap2, double, double)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd3, bidimap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d3, deque3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm3, hmap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs3, hset3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h3, heap3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih3, iheap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll3, linked3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(LIST, l3, list3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm3, mmap3, size_t, size_t)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms3, mset3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(STACK, s3, stack3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl3, sotredlist3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q3, queue3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts3, tset3, /* K */, size_t)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm3, tmap3, size_t, size_t)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd4, bidimap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d4, deque4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm4, hmap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs4, hset4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h4, heap4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih4, iheap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll4, linked4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(LIST, l4, list4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm4, mmap4, enum app_state, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms4, mset4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(STACK, s4, stack4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl4, sotredlist4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q4, queue4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts4, tset4, /* K */, enum app_state)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm4, tmap4, enum app_state, enum app_state)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd5, bidimap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d5, deque5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm5, hmap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs5, hset5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h5, heap5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih5, iheap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll5, linked5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l5, list5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm5, mmap5, void *, void *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms5, mset5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s5, stack5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl5, sotredlist5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q5, queue5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts5, tset5, /* K */, void *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm5, tmap5, void *, void *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd6, bidimap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d6, deque6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm6, hmap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs6, hset6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h6, heap6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih6, iheap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll6, linked6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l6, list6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm6, mmap6, int *, int *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms6, mset6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s6, stack6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl6, sotredlist6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q6, queue6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts6, tset6, /* K */, int *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm6, tmap6, int *, int *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd7, bidimap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d7, deque7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm7, hmap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs7, hset7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h7, heap7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih7, iheap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll7, linked7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l7, list7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm7, mmap7, struct imaginary *, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms7, mset7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s7, stack7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl7, sotredlist7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q7, queue7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts7, tset7, /* K */, struct imaginary *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm7, tmap7, struct imaginary *, struct imaginary *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd8, bidimap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d8, deque8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm8, hmap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs8, hset8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h8, heap8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih8, iheap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll8, linked8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l8, list8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm8, mmap8, double *, double *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms8, mset8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s8, stack8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl8, sotredlist8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q8, queue8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts8, tset8, /* K */, double *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm8, tmap8, double *, double *)
|
||||
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bd9, bidimap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(DEQUE, d9, deque9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hm9, hmap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(HASHSET, hs9, hset9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(HEAP, h9, heap9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(INTERVALHEAP, ih9, iheap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(LINKEDLIST, ll9, linked9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(LIST, l9, list9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mm9, mmap9, enum app_state *, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(MULTISET, ms9, mset9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(STACK, s9, stack9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(SORTEDLIST, sl9, sotredlist9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(QUEUE, q9, queue9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(TREESET, ts9, tset9, /* K */, enum app_state *)
|
||||
CMC_COLLECTION_GENERATE(TREEMAP, tm9, tmap9, enum app_state *, enum app_state *)
|
||||
@@ -1,433 +0,0 @@
|
||||
#include <macro_collections.h>
|
||||
|
||||
/**
|
||||
* HashMap, MultiMap and BidiMap use hashtables with different strategies. This
|
||||
* benchmark is aimed to explore the pros and cons of each implementation.
|
||||
*
|
||||
* HashMap - A plain hashtable with no indirection using linear probing and
|
||||
* robin hood hashing.
|
||||
* Expectations:
|
||||
* - Constant memory usage which leads to high memory usage per element
|
||||
* ratio when the hashtable has few elements but the ratio is
|
||||
* somewhat good as it starts to fill up;
|
||||
* - Faster lookup due to no indirection and good caching;
|
||||
* - Faster insertion and removal due to no calls to free or malloc.
|
||||
*
|
||||
* MultiMap - A hashtable using separate chaining where each bucket is a doubly
|
||||
* linked list.
|
||||
* Expectations:
|
||||
* - High memory usage per element ratio due to the double linked
|
||||
* lists;
|
||||
* - Pointer indirection might lead to slower lookup and poor caching
|
||||
* due to using nodes to store the key and the value;
|
||||
* - A bit slower insertion and removal as calls to free and malloc are
|
||||
* needed.
|
||||
*
|
||||
* BidiMap - Two arrays, one representing the key set and one the value set.
|
||||
* Each array is made of pointers to an entry. This way one entry can
|
||||
* be referenced by both the key set and the value set using only one
|
||||
* node. Uses robin hood hashing to adjust the pointers.
|
||||
* Expectations:
|
||||
* - Overrall low memory usage compared to other implementations;
|
||||
* - Pointer indirection might lead to slower lookupand poor caching
|
||||
* due to using nodes to store the key and the value;
|
||||
* - Very slow insertion and removal as a node needs to be added or
|
||||
* removed on both arrays.
|
||||
*/
|
||||
|
||||
/* Generate Code */
|
||||
CMC_COLLECTION_GENERATE(HASHMAP, hmap, hmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(MULTIMAP, mmap, mmap, int, int)
|
||||
CMC_COLLECTION_GENERATE(BIDIMAP, bmap, bmap, int, int)
|
||||
|
||||
/* Forward declaration of benchmarks */
|
||||
void benchmark_bidimap(const char *collection, int total_elements,
|
||||
double load_factor);
|
||||
void benchmark_hashmap(const char *collection, int total_elements,
|
||||
double load_factor);
|
||||
void benchmark_multimap(const char *collection, int total_elements,
|
||||
double load_factor);
|
||||
|
||||
/* Comparator and Hash function */
|
||||
int cmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
size_t hash(int a)
|
||||
{
|
||||
size_t x = (size_t)a;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = (x >> 16) ^ x;
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Custom allocators to count memory usage */
|
||||
size_t total_memory = 0;
|
||||
|
||||
/* Report Functions */
|
||||
void print_overview(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("Overview\n"
|
||||
" Collection : %s\n"
|
||||
" Total Elements : %d\n"
|
||||
" Load Factor : %.4lf\n\n",
|
||||
collection, total_elements, load_factor);
|
||||
}
|
||||
|
||||
void print_time(const char *collection, double C, double R, double U, double D)
|
||||
{
|
||||
/* C - Create, R - Read, U - Update, D - Delete */
|
||||
printf("Time [%s]: \n"
|
||||
" Total : %8.0lf milliseconds \n"
|
||||
" Create : %8.0lf milliseconds\n"
|
||||
" Read : %8.0lf milliseconds\n"
|
||||
" Update : %8.0lf milliseconds\n"
|
||||
" Delete : %8.0lf milliseconds\n\n",
|
||||
collection, C + R + U + D, C, R, U, D);
|
||||
}
|
||||
|
||||
void print_memory(const char *s, size_t memory[11], int partition_size)
|
||||
{
|
||||
printf("Each Partition : %d elements\n\n", partition_size);
|
||||
|
||||
for (size_t i = 0; i < 11; i++)
|
||||
{
|
||||
printf(" %3" PRIuMAX "%% : %12" PRIuMAX " B | %10" PRIuMAX " kB | %8" PRIuMAX " MB (+ %2.0lf%%)\n",
|
||||
i * 10, memory[i], memory[i] / 1000, memory[i] / 1000000, (1 - ((double)memory[0] / (double)memory[i])) * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom allocation functions */
|
||||
void *my_malloc(size_t size)
|
||||
{
|
||||
void *result = malloc(size);
|
||||
|
||||
if (result)
|
||||
total_memory += size;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *my_calloc(size_t count, size_t size)
|
||||
{
|
||||
void *result = calloc(count, size);
|
||||
|
||||
if (result)
|
||||
total_memory += count * size;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *my_realloc(void *buffer, size_t size)
|
||||
{
|
||||
/* This assumes that this benchmark never uses realloc */
|
||||
return realloc(buffer, size);
|
||||
}
|
||||
|
||||
void my_free(void *block)
|
||||
{
|
||||
free(block);
|
||||
}
|
||||
|
||||
/* Default custom allocation node */
|
||||
struct cmc_alloc_node alloc_default = { .malloc = my_malloc,
|
||||
.calloc = my_calloc,
|
||||
.realloc = my_realloc,
|
||||
.free = my_free };
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 4)
|
||||
{
|
||||
fprintf(
|
||||
stderr,
|
||||
"Usage:\n"
|
||||
" %s collection_name total_elements load_factor\n"
|
||||
"\nOPTIONS\n"
|
||||
" - collection_name : (BIDIMAP|HASHMAP|MULTIMAP|ALL)\n"
|
||||
" - total_elements : Total elements to be added to the hashtable (int > 0)\n"
|
||||
" - load_factor : The hashtable's load factor (0 < l < 1.0)\n",
|
||||
argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int total_elements = atoi(argv[2]);
|
||||
double load_factor = atof(argv[3]);
|
||||
|
||||
bool error = false;
|
||||
|
||||
if (total_elements < 1)
|
||||
{
|
||||
error = true;
|
||||
fprintf(stderr, "Invalid value for total_elements: %s\n", argv[2]);
|
||||
}
|
||||
|
||||
if (load_factor <= 0.0 || load_factor >= 1.0)
|
||||
{
|
||||
error = true;
|
||||
fprintf(stderr, "Invalid value for load_factor: %s\n", argv[3]);
|
||||
}
|
||||
|
||||
if (error)
|
||||
return 1;
|
||||
|
||||
const char *collection = argv[1];
|
||||
|
||||
if (strcmp(collection, "BIDIMAP") == 0)
|
||||
{
|
||||
benchmark_bidimap(collection, total_elements, load_factor);
|
||||
}
|
||||
else if (strcmp(collection, "HASHMAP") == 0)
|
||||
{
|
||||
benchmark_hashmap(collection, total_elements, load_factor);
|
||||
}
|
||||
else if (strcmp(collection, "MULTIMAP") == 0)
|
||||
{
|
||||
benchmark_multimap(collection, total_elements, load_factor);
|
||||
}
|
||||
else if (strcmp(collection, "ALL") == 0)
|
||||
{
|
||||
benchmark_bidimap("BIDIMAP", total_elements, load_factor);
|
||||
benchmark_hashmap("HASHMAP", total_elements, load_factor);
|
||||
benchmark_multimap("MULTIMAP", total_elements, load_factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Unknown parameter collection_name = %s\n", collection);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void benchmark_bidimap(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
total_memory = 0;
|
||||
|
||||
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
|
||||
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
|
||||
int partition = total_elements / 10;
|
||||
|
||||
print_overview(collection, total_elements, load_factor);
|
||||
|
||||
struct bmap *map = bmap_new_custom(total_elements, load_factor, cmp, hash,
|
||||
cmp, hash, &alloc_default, NULL);
|
||||
|
||||
/* Create, Read, Update, Delete */
|
||||
struct cmc_timer timers[4] = { 0 };
|
||||
|
||||
/* Memory Usage 0%, 10%, 20%, ... 100% */
|
||||
size_t memory[11] = {0};
|
||||
|
||||
memory[0] = total_memory;
|
||||
|
||||
/* Create */
|
||||
cmc_timer_start(timers[0]);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
for (int j = partition * i; j < partition * (i + 1); j++)
|
||||
{
|
||||
bmap_insert(map, j, j);
|
||||
}
|
||||
|
||||
memory[i + 1] = total_memory;
|
||||
}
|
||||
|
||||
cmc_timer_stop(timers[0]);
|
||||
cmc_timer_calc(timers[0]);
|
||||
/* Create End */
|
||||
|
||||
/* Read */
|
||||
cmc_timer_start(timers[1]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
bmap_contains_key(map, i);
|
||||
|
||||
cmc_timer_stop(timers[1]);
|
||||
cmc_timer_calc(timers[1]);
|
||||
/* Read End */
|
||||
|
||||
/* Update */
|
||||
cmc_timer_start(timers[2]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
bmap_update_val_by_key(map, i, total_elements - i - 1);
|
||||
|
||||
cmc_timer_stop(timers[2]);
|
||||
cmc_timer_calc(timers[2]);
|
||||
/* Update End */
|
||||
|
||||
/* Delete */
|
||||
cmc_timer_start(timers[3]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
bmap_remove_by_key(map, i, NULL, NULL);
|
||||
|
||||
cmc_timer_stop(timers[3]);
|
||||
cmc_timer_calc(timers[3]);
|
||||
/* Delete End */
|
||||
|
||||
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
|
||||
timers[3].result);
|
||||
|
||||
print_memory(collection, memory, partition);
|
||||
|
||||
bmap_free(map, NULL);
|
||||
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
void benchmark_hashmap(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
total_memory = 0;
|
||||
|
||||
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
|
||||
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
|
||||
int partition = total_elements / 10;
|
||||
|
||||
print_overview(collection, total_elements, load_factor);
|
||||
|
||||
struct hmap *map = hmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
|
||||
|
||||
/* Create, Read, Update, Delete */
|
||||
struct cmc_timer timers[4] = { 0 };
|
||||
|
||||
/* Memory Usage 0%, 10%, 20%, ... 100% */
|
||||
size_t memory[11] = {0};
|
||||
|
||||
memory[0] = total_memory;
|
||||
|
||||
/* Create */
|
||||
cmc_timer_start(timers[0]);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
for (int j = partition * i; j < partition * (i + 1); j++)
|
||||
{
|
||||
hmap_insert(map, j, j);
|
||||
}
|
||||
|
||||
memory[i + 1] = total_memory;
|
||||
}
|
||||
|
||||
cmc_timer_stop(timers[0]);
|
||||
cmc_timer_calc(timers[0]);
|
||||
/* Create End */
|
||||
|
||||
/* Read */
|
||||
cmc_timer_start(timers[1]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
hmap_contains(map, i);
|
||||
|
||||
cmc_timer_stop(timers[1]);
|
||||
cmc_timer_calc(timers[1]);
|
||||
/* Read End */
|
||||
|
||||
/* Update */
|
||||
cmc_timer_start(timers[2]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
hmap_update(map, i, total_elements - i - 1, NULL);
|
||||
|
||||
cmc_timer_stop(timers[2]);
|
||||
cmc_timer_calc(timers[2]);
|
||||
/* Update End */
|
||||
|
||||
/* Delete */
|
||||
cmc_timer_start(timers[3]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
hmap_remove(map, i, NULL);
|
||||
|
||||
cmc_timer_stop(timers[3]);
|
||||
cmc_timer_calc(timers[3]);
|
||||
/* Delete End */
|
||||
|
||||
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
|
||||
timers[3].result);
|
||||
|
||||
print_memory(collection, memory, partition);
|
||||
|
||||
hmap_free(map, NULL);
|
||||
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
}
|
||||
|
||||
void benchmark_multimap(const char *collection, int total_elements,
|
||||
double load_factor)
|
||||
{
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
total_memory = 0;
|
||||
|
||||
/* Normalize total_elements to be a multiple of 10 and calculate partition size */
|
||||
total_elements = total_elements % 10 == 0 ? total_elements : total_elements + (10 - total_elements % 10);
|
||||
int partition = total_elements / 10;
|
||||
|
||||
print_overview(collection, total_elements, load_factor);
|
||||
|
||||
struct mmap *map = mmap_new_custom(total_elements, load_factor, cmp, hash, &alloc_default, NULL);
|
||||
|
||||
/* Create, Read, Update, Delete */
|
||||
struct cmc_timer timers[4] = { 0 };
|
||||
|
||||
/* Memory Usage 0%, 10%, 20%, ... 100% */
|
||||
size_t memory[11] = {0};
|
||||
|
||||
memory[0] = total_memory;
|
||||
|
||||
/* Create */
|
||||
cmc_timer_start(timers[0]);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
for (int j = partition * i; j < partition * (i + 1); j++)
|
||||
{
|
||||
mmap_insert(map, j, j);
|
||||
}
|
||||
|
||||
memory[i + 1] = total_memory;
|
||||
}
|
||||
|
||||
cmc_timer_stop(timers[0]);
|
||||
cmc_timer_calc(timers[0]);
|
||||
/* Create End */
|
||||
|
||||
/* Read */
|
||||
cmc_timer_start(timers[1]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
mmap_contains(map, i);
|
||||
|
||||
cmc_timer_stop(timers[1]);
|
||||
cmc_timer_calc(timers[1]);
|
||||
/* Read End */
|
||||
|
||||
/* Update */
|
||||
cmc_timer_start(timers[2]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
mmap_update(map, i, total_elements - i - 1, NULL);
|
||||
|
||||
cmc_timer_stop(timers[2]);
|
||||
cmc_timer_calc(timers[2]);
|
||||
/* Update End */
|
||||
|
||||
/* Delete */
|
||||
cmc_timer_start(timers[3]);
|
||||
for (int i = 0; i < total_elements; i++)
|
||||
mmap_remove(map, i, NULL);
|
||||
|
||||
cmc_timer_stop(timers[3]);
|
||||
cmc_timer_calc(timers[3]);
|
||||
/* Delete End */
|
||||
|
||||
print_time(collection, timers[0].result, timers[1].result, timers[2].result,
|
||||
timers[3].result);
|
||||
|
||||
print_memory(collection, memory, partition);
|
||||
|
||||
mmap_free(map, NULL);
|
||||
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
CFLAGS = -Wall -Wextra
|
||||
INCLUDE = ../../src
|
||||
|
||||
main:
|
||||
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DCMC_QUEUE
|
||||
a.exe
|
||||
gcc queue.c -I $(INCLUDE) $(CFLAGS) -o a.exe -DSAC_QUEUE
|
||||
a.exe
|
||||
@@ -1,76 +0,0 @@
|
||||
/**
|
||||
* queue.c
|
||||
*
|
||||
* Creation Date: 24/06/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/* Showing off how different queue implementations affect runtime cost */
|
||||
|
||||
#include "utl/timer.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#define MAX 200000
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
#include "cmc/queue.h"
|
||||
CMC_GENERATE_QUEUE(q, queue, int)
|
||||
#define TARGET "QUEUE"
|
||||
#elif defined(SAC_QUEUE)
|
||||
#include "sac/queue.h"
|
||||
SAC_QUEUE_GENERATE(q, queue, , int, MAX)
|
||||
#define TARGET "SAC QUEUE"
|
||||
#else
|
||||
#error Please define either CMC_QUEUE, SAC_QUEUE or EXT_QUEUE
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
struct queue *q = q_new(MAX);
|
||||
#elif defined(SAC_QUEUE)
|
||||
queue _q = q_new();
|
||||
queue_ptr q = &_q;
|
||||
#endif
|
||||
|
||||
size_t sum = 0;
|
||||
int i = 0;
|
||||
|
||||
struct cmc_timer timer;
|
||||
cmc_timer_start(timer);
|
||||
|
||||
while (q_count(q) != MAX)
|
||||
{
|
||||
q_enqueue(q, i++);
|
||||
|
||||
if (i % 10 == 0)
|
||||
{
|
||||
for (size_t i = 0; i < 9; i++)
|
||||
{
|
||||
sum += q_peek(q);
|
||||
q_dequeue(q);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cmc_timer_stop(timer);
|
||||
cmc_timer_calc(timer);
|
||||
|
||||
printf("----------------------------------------\n");
|
||||
printf("%s\n", TARGET);
|
||||
printf("Execution time: %.0lf milliseconds\n", timer.result);
|
||||
printf("SUM: %" PRIuMAX "\n", sum);
|
||||
printf("----------------------------------------\n");
|
||||
|
||||
#if defined(CMC_QUEUE)
|
||||
q_free(q, NULL);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/**
|
||||
* twister.c
|
||||
*
|
||||
* Creation Date: 09/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Mersenne Twister PRNG utility
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define NN 312
|
||||
#define MM 156
|
||||
#define MATRIX_A UINT64_C(0xB5026F5AA96619E9)
|
||||
#define UM UINT64_C(0xFFFFFFFF80000000) // Most significant 33 bits
|
||||
#define LM UINT64_C(0x7FFFFFFF) // Least significant 31 bits
|
||||
|
||||
// State vector
|
||||
typedef struct mt_state_s
|
||||
{
|
||||
uint64_t mt[NN];
|
||||
int mti;
|
||||
} mt_state, *mt_state_ptr;
|
||||
|
||||
// Initializes mt[NN] with a seed
|
||||
void twist_init(mt_state_ptr st, uint64_t seed);
|
||||
|
||||
// Generates a random uint64_t in [0, 2^64-1] interval
|
||||
uint64_t twist_uint64(mt_state_ptr st);
|
||||
|
||||
// Generates a double in [0, 1) interval
|
||||
double twist_real(mt_state_ptr st);
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
||||
// Initialize a state mt[NN] with a seed
|
||||
void twist_init(mt_state_ptr st, uint64_t seed)
|
||||
{
|
||||
st->mti = NN + 1;
|
||||
|
||||
st->mt[0] = seed;
|
||||
|
||||
for (st->mti = 1; st->mti < NN; st->mti++)
|
||||
{
|
||||
st->mt[st->mti] = (UINT64_C(6364136223846793005) * (st->mt[st->mti - 1] ^ (st->mt[st->mti - 1] >> 62)) + st->mti);
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a random uint64_t in [0, 2^64-1] interval
|
||||
uint64_t twist_uint64(mt_state_ptr st)
|
||||
{
|
||||
int i;
|
||||
uint64_t x;
|
||||
static uint64_t mag01[2] = {UINT64_C(0), MATRIX_A};
|
||||
|
||||
if (st->mti >= NN)
|
||||
{
|
||||
// Generate NN words at one time if twist_init() has not been called
|
||||
// A default initial seed is used
|
||||
if (st->mti == NN + 1)
|
||||
twist_init(st, UINT64_C(5489));
|
||||
|
||||
for (i = 0; i < NN - MM; i++)
|
||||
{
|
||||
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
|
||||
st->mt[i] = st->mt[i + MM] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
}
|
||||
|
||||
for (; i < NN - 1; i++)
|
||||
{
|
||||
x = (st->mt[i] & UM) | (st->mt[i + 1] & LM);
|
||||
st->mt[i] = st->mt[i + (MM - NN)] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
}
|
||||
|
||||
x = (st->mt[NN - 1] & UM) | (st->mt[0] & LM);
|
||||
|
||||
st->mt[NN - 1] = st->mt[MM - 1] ^ (x >> 1) ^ mag01[(int)(x & UINT64_C(1))];
|
||||
|
||||
st->mti = 0;
|
||||
}
|
||||
|
||||
x = st->mt[st->mti++];
|
||||
|
||||
x ^= (x >> 29) & UINT64_C(0x5555555555555555);
|
||||
x ^= (x << 17) & UINT64_C(0x71D67FFFEDA60000);
|
||||
x ^= (x << 37) & UINT64_C(0xFFF7EEE000000000);
|
||||
x ^= (x >> 43);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Generates a double in [0, 1) interval
|
||||
double twist_real(mt_state_ptr st)
|
||||
{
|
||||
return (twist_uint64(st) >> 11) * (1.0 / 9007199254740992.0);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
# Examples
|
||||
|
||||
* deque - DEQUE collection examples
|
||||
* hashmap - HASHMAP collection examples
|
||||
* hashset - HASHSET collection examples
|
||||
* heap - HEAP collection examples
|
||||
* iterators - Examples of using the collection's iterators
|
||||
* linkedlist - LINKEDLIST collection examples
|
||||
* list - LIST collection examples
|
||||
* multimap - MULTIMAP collection examples
|
||||
* multiset - MULTISET collection examples
|
||||
* others - Other examples, generally more robust and using multiple collections
|
||||
* queue - QUEUE collection examples
|
||||
* stack - STACK collection examples
|
||||
* treemap - TREEMAP collection examples
|
||||
* treeset - TREESET collection examples
|
||||
@@ -1,4 +0,0 @@
|
||||
# Deque examples
|
||||
|
||||
* even_odd.c - separates odd numbers to one end of the deque and even number to the other. Sum only half of it to give the total sum of even numbers.
|
||||
* iterator.c - A complete example of the deque iterator
|
||||
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* even_odd.c
|
||||
*
|
||||
* Creation Date: 03/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/deque.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
CMC_GENERATE_DEQUE(d, deque, size_t);
|
||||
typedef struct deque deque;
|
||||
typedef struct deque_iter deque_iter;
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// 1- Add odd numbers to the start of the deque and even numbers to the end.
|
||||
// 2- Iterate over the deque, starting from the end, until index is half
|
||||
// the deque count and stop.
|
||||
// 3- Sum of all even numbers
|
||||
|
||||
deque *numbers = d_new(1000);
|
||||
|
||||
for (size_t i = 1; i <= 100000; i++)
|
||||
{
|
||||
i % 2 == 0 ? d_push_back(numbers, i) : d_push_front(numbers, i);
|
||||
}
|
||||
|
||||
deque_iter iter;
|
||||
d_iter_init(&iter, numbers);
|
||||
|
||||
size_t result, index, sum = 0;
|
||||
|
||||
for (d_iter_to_end(&iter); !d_iter_start(&iter); d_iter_prev(&iter))
|
||||
{
|
||||
result = d_iter_value(&iter);
|
||||
index = d_iter_index(&iter);
|
||||
|
||||
if ((double)index < (double)d_count(numbers) / 2.0)
|
||||
break;
|
||||
|
||||
sum += result;
|
||||
}
|
||||
|
||||
printf("Total sum: %lu\n", sum);
|
||||
|
||||
assert(sum == 2500050000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,201 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 13/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/deque.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a deque of integers
|
||||
CMC_GENERATE_DEQUE(d, deque, size_t);
|
||||
typedef struct deque deque;
|
||||
typedef struct deque_iter deque_iter;
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new deque with an initial capacity of 100
|
||||
deque *my_deque = d_new(100);
|
||||
|
||||
// Add elements to the deque
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
// Add odd numbers to the front, even numbers to the back.
|
||||
if (i % 2 == 0)
|
||||
d_push_front(my_deque, i);
|
||||
else
|
||||
d_push_back(my_deque, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (front index) to the end (rear index) of the deque
|
||||
for (deque_iter it = my_deque->it_start(my_deque); // Initialize iterator 'it' to the start of the deque
|
||||
!d_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
d_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = d_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
// Print deque
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == d_count(my_deque) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = d_count(my_deque) / 2;
|
||||
for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = d_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
// Print deque up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the deque
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (deque_iter it = my_deque->it_end(my_deque); // Initialize iterator 'it' to the end of the deque
|
||||
!d_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
d_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = d_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
// Print deque
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == d_count(my_deque) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
deque_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the deque [ my_deque->it_start() and my_deque->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_deque->it_start(my_deque);
|
||||
it = my_deque->it_end(my_deque);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
d_iter_init(&it, my_deque);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
deque_iter *iter = d_iter_new(my_deque);
|
||||
|
||||
// The actual while loop
|
||||
while (!d_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = d_iter_value(iter);
|
||||
size_t i = d_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("deque[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
d_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the deque
|
||||
d_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the deque
|
||||
d_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!d_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = d_iter_value(iter);
|
||||
size_t i = d_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("deque[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
d_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 3 to the number 7
|
||||
for (d_iter_to_start(&it); !d_iter_end(&it); d_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
size_t *r = d_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 3 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (deque_iter it = my_deque->it_start(my_deque); !d_iter_end(&it); d_iter_next(&it))
|
||||
{
|
||||
int e = d_iter_value(&it);
|
||||
size_t i = d_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == d_count(my_deque) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by d_iter_new()
|
||||
d_iter_free(iter);
|
||||
// Dispose the deque created
|
||||
d_free(my_deque, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
* Example of In-Order Depth-First Search using:
|
||||
* - A Stack
|
||||
* - Recursion
|
||||
* - Without both
|
||||
*/
|
||||
|
||||
#define CMC_CAMEL_CASE
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
C_MACRO_COLLECTIONS_GEN(CMC, TREESET, (tree, BinaryTree, , , int32_t), (ITER, STR))
|
||||
|
||||
#define MYSTACK (stk, Stack, , , struct BinaryTreeNode *)
|
||||
|
||||
C_MACRO_COLLECTIONS(CMC, STACK, CORE, STRUCT, MYSTACK)
|
||||
C_MACRO_COLLECTIONS(CMC, STACK, CORE, HEADER, MYSTACK)
|
||||
C_MACRO_COLLECTIONS(CMC, STACK, CORE, SOURCE, MYSTACK)
|
||||
|
||||
void DFS(struct BinaryTreeNode *root)
|
||||
{
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
DFS(root->left);
|
||||
|
||||
fprintf(stdout, "%d ", root->value);
|
||||
|
||||
DFS(root->right);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct BinaryTree *tree = tree_new(&(struct BinaryTreeFVal){ .cmp = cmc_i32_cmp, .str = cmc_i32_str, NULL });
|
||||
|
||||
for (int i = 1; i <= 10; i++)
|
||||
tree_insert(tree, i);
|
||||
|
||||
int32_t result = 1;
|
||||
|
||||
cmc_assert(tree_min(tree, &result));
|
||||
cmc_assert_equals(int32_t, 1, result);
|
||||
|
||||
cmc_assert(tree_max(tree, &result));
|
||||
cmc_assert_equals(int32_t, 10, result);
|
||||
|
||||
printf("Without Recursion or Stack:\n");
|
||||
tree_print(tree, stdout, "[ ", " ", " ]\n");
|
||||
|
||||
printf("Recursion:\n");
|
||||
fprintf(stdout, "[ ");
|
||||
DFS(tree->root);
|
||||
fprintf(stdout, "]\n");
|
||||
|
||||
printf("Stack:\n");
|
||||
fprintf(stdout, "[ ");
|
||||
struct Stack *stack = stk_new(100, &(struct StackFVal){ NULL });
|
||||
|
||||
struct BinaryTreeNode *node = tree->root;
|
||||
|
||||
while (node || !stk_empty(stack))
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
if (!stk_push(stack, node))
|
||||
cmc_log_error("Could not push to stack %d\n", cmc_flags_to_str[stk_flag(stack)]);
|
||||
|
||||
node = node->left;
|
||||
}
|
||||
else
|
||||
{
|
||||
node = stk_top(stack);
|
||||
|
||||
if (!stk_pop(stack))
|
||||
cmc_log_error("Could not pop from the stack %s\n", cmc_flags_to_str[stk_flag(stack)]);
|
||||
|
||||
fprintf(stdout, "%d ", node->value);
|
||||
|
||||
node = node->right;
|
||||
}
|
||||
}
|
||||
|
||||
stk_free(stack);
|
||||
fprintf(stdout, "]\n");
|
||||
|
||||
tree_free(tree);
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
// This is the master header. This will include every feature of the library.
|
||||
// This comes with many helper macros (high level API) and utility functions.
|
||||
#include "macro_collections.h"
|
||||
|
||||
// A PARAM is a standard way to pass required parameters to the lower level API.
|
||||
// It is a tuple of form (PFX, SNAME, SIZE, K, V). In this case, not all of them
|
||||
// are used, so we can leave them empty. We are creating a list of value int.
|
||||
#define MY_LIST_PARAMS (intl, int_list, , , int)
|
||||
|
||||
// High level API. Generate a LIST from the CMC library with the STR extension
|
||||
// using our previously defined PARAMs. Every collections has a CORE part that
|
||||
// needs to be generated first. Then, we can add other parts after. This macro
|
||||
// does all of that for us. The STR part will provide us with a function that
|
||||
// will be used later.
|
||||
C_MACRO_COLLECTIONS_EXTENDED(CMC, LIST, MY_LIST_PARAMS, (STR))
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Our list type is defined by SNAME and all functions are prefixed by PFX
|
||||
// (PFX can also be thought as the function's namespace). Also, nodes,
|
||||
// entries, iterators and other structures are prefixed by SNAME. So PFX is
|
||||
// for functions and SNAME is for structs, where the main one is simply
|
||||
// 'struct SNAME'.
|
||||
// To initialize a list we need to pass in an initial capacity and something
|
||||
// that is called a function table for the V type.
|
||||
// This function table is a struct with methods that will extract some
|
||||
// (sometimes) necessary behaviour from your custom data type. Things like
|
||||
// hash, comparison and printing. A list doesn't require any of these
|
||||
// functions. That is, the CORE module doesn't use any of them.
|
||||
// But since we are using the STR module, we will need to define the 'str'
|
||||
// function. luckily, for the 'int' type, the library already provides such
|
||||
// function (cmc_i32_str), provided by the /utl/futils.h header file.
|
||||
struct int_list *list = intl_new(32, &(struct int_list_fval){ .str = cmc_i32_str, NULL });
|
||||
|
||||
// Check if the list was successfully initialized. It could fail if the
|
||||
// initial capacity is too big or if 'struct int_list_fval *' is NULL,
|
||||
// because every data structure must have a valid function table.
|
||||
if (!list)
|
||||
return 1;
|
||||
|
||||
// Add some items to the list. The CMC data structures are all dynamically
|
||||
// sized. So there can be as many items as you want as long as you have
|
||||
// enough memory.
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Try to add an element to the list. If it fails you can check what
|
||||
// caused it by getting its flag.
|
||||
if (!intl_push_back(list, i))
|
||||
{
|
||||
enum cmc_flags flag = intl_flag(list);
|
||||
// Use cmc_flags_to_str to map the enum error to a string.
|
||||
fprintf(stderr, "%s : push_back failed\n", cmc_flags_to_str[flag]);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we will use the STR module, the _print() function. This is where the
|
||||
// '.str' from the function table comes into play. If we haven't defined it,
|
||||
// the program would've crashed. We also need to define to which file we
|
||||
// will be printing the list's content. In this case, the terminal. Also,
|
||||
// some strings need to be defined. They will be printed: before all elements,
|
||||
// between each one, and after all elements. This is very usefull and can
|
||||
// print a data structure very nicely.
|
||||
intl_print(list, stdout, "[ ", ", ", " ]\n");
|
||||
|
||||
// Free all of its resources
|
||||
intl_free(list);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#include "macro_collections.h"
|
||||
|
||||
#define MYSTACK (stk, stack, , , int)
|
||||
|
||||
C_MACRO_COLLECTIONS(CMC, STACK, CORE, STRUCT, MYSTACK)
|
||||
C_MACRO_COLLECTIONS(CMC, STACK, CORE, HEADER, MYSTACK)
|
||||
C_MACRO_COLLECTIONS(CMC, STACK, CORE, SOURCE, MYSTACK)
|
||||
|
||||
struct
|
||||
{
|
||||
struct stack *from;
|
||||
struct stack *aux;
|
||||
struct stack *to;
|
||||
} print_aux = { NULL };
|
||||
|
||||
void print_stacks()
|
||||
{
|
||||
for (int i = 9; i >= 0; i--)
|
||||
{
|
||||
int ia = print_aux.from->buffer[i];
|
||||
int ib = print_aux.aux->buffer[i];
|
||||
int ic = print_aux.to->buffer[i];
|
||||
|
||||
printf("| %c | %c | %c |\n", ia == 0 ? 32 : ia + 48, ib == 0 ? 32 : ib + 48, ic == 0 ? 32 : ic + 48);
|
||||
}
|
||||
|
||||
printf("+---+---+---+\n\n");
|
||||
}
|
||||
|
||||
void move(struct stack *from, struct stack *to)
|
||||
{
|
||||
stk_push(to, stk_top(from));
|
||||
|
||||
stk_pop(from);
|
||||
}
|
||||
|
||||
void hanoi(int n, struct stack *from, struct stack *aux, struct stack *to)
|
||||
{
|
||||
if (n == 0)
|
||||
return;
|
||||
|
||||
hanoi(n - 1, from, to, aux);
|
||||
|
||||
move(from, to);
|
||||
|
||||
print_stacks();
|
||||
|
||||
hanoi(n - 1, aux, from, to);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
struct stack *from = stk_new(10, &(struct stack_fval){ NULL });
|
||||
struct stack *to = stk_new(10, &(struct stack_fval){ NULL });
|
||||
struct stack *aux = stk_new(10, &(struct stack_fval){ NULL });
|
||||
|
||||
for (int i = 4; i >= 1; i--)
|
||||
stk_push(from, i);
|
||||
|
||||
print_aux.from = from;
|
||||
print_aux.aux = aux;
|
||||
print_aux.to = to;
|
||||
|
||||
print_stacks();
|
||||
|
||||
hanoi(stk_count(from), from, aux, to);
|
||||
|
||||
stk_free(from);
|
||||
stk_free(to);
|
||||
stk_free(aux);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
# Hashmap examples
|
||||
|
||||
* countries - Uses a hashmap to map the country name to its population
|
||||
* foreach.c - ForEach macro example
|
||||
* iterator.c - A complete example of the hashmap iterator
|
||||
@@ -1,216 +0,0 @@
|
||||
Afghanistan,34656032
|
||||
Albania,2876101
|
||||
Algeria,40606052
|
||||
American Samoa,55599
|
||||
Andorra,77281
|
||||
Angola,28813463
|
||||
Antigua and Barbuda,100963
|
||||
Argentina,43847430
|
||||
Armenia,2924816
|
||||
Aruba,104822
|
||||
Australia,24127159
|
||||
Austria,8747358
|
||||
Azerbaijan,9762274
|
||||
Bahamas; The,391232
|
||||
Bahrain,1425171
|
||||
Bangladesh,162951560
|
||||
Barbados,284996
|
||||
Belarus,9507120
|
||||
Belgium,11348159
|
||||
Belize,366954
|
||||
Benin,10872298
|
||||
Bermuda,65331
|
||||
Bhutan,797765
|
||||
Bolivia,10887882
|
||||
Bosnia and Herzegovina,3516816
|
||||
Botswana,2250260
|
||||
Brazil,207652865
|
||||
British Virgin Islands,30661
|
||||
Brunei Darussalam,423196
|
||||
Bulgaria,7127822
|
||||
Burkina Faso,18646433
|
||||
Burundi,10524117
|
||||
Cabo Verde,539560
|
||||
Cambodia,15762370
|
||||
Cameroon,23439189
|
||||
Canada,36286425
|
||||
Cayman Islands,60765
|
||||
Central African Republic,4594621
|
||||
Chad,14452543
|
||||
Channel Islands,164541
|
||||
Chile,17909754
|
||||
China,1378665000
|
||||
Colombia,48653419
|
||||
Comoros,795601
|
||||
Congo; Dem. Rep.,78736153
|
||||
Congo; Rep.,5125821
|
||||
Costa Rica,4857274
|
||||
Cote d'Ivoire,23695919
|
||||
Croatia,4170600
|
||||
Cuba,11475982
|
||||
Curacao,159999
|
||||
Cyprus,1170125
|
||||
Czech Republic,10561633
|
||||
Denmark,5731118
|
||||
Djibouti,942333
|
||||
Dominica,73543
|
||||
Dominican Republic,10648791
|
||||
Ecuador,16385068
|
||||
Egypt; Arab Rep.,95688681
|
||||
El Salvador,6344722
|
||||
Equatorial Guinea,1221490
|
||||
Estonia,1316481
|
||||
Ethiopia,102403196
|
||||
Faroe Islands,49117
|
||||
Fiji,898760
|
||||
Finland,5495096
|
||||
France,66896109
|
||||
French Polynesia,280208
|
||||
Gabon,1979786
|
||||
Gambia; The,2038501
|
||||
Georgia,3719300
|
||||
Germany,82667685
|
||||
Ghana,28206728
|
||||
Gibraltar,34408
|
||||
Greece,10746740
|
||||
Greenland,56186
|
||||
Grenada,107317
|
||||
Guam,162896
|
||||
Guatemala,16582469
|
||||
Guinea,12395924
|
||||
Guinea-Bissau,1815698
|
||||
Guyana,773303
|
||||
Haiti,10847334
|
||||
Honduras,9112867
|
||||
Hong Kong SAR; China,7346700
|
||||
Hungary,9817958
|
||||
Iceland,334252
|
||||
India,1324171354
|
||||
Indonesia,261115456
|
||||
Iran; Islamic Rep.,80277428
|
||||
Iraq,37202572
|
||||
Ireland,4773095
|
||||
Isle of Man,83737
|
||||
Israel,8547100
|
||||
Italy,60600590
|
||||
Jamaica,2881355
|
||||
Japan,126994511
|
||||
Jordan,9455802
|
||||
Kazakhstan,17797032
|
||||
Kenya,48461567
|
||||
Kiribati,114395
|
||||
Korea; Dem. People’s Rep.,25368620
|
||||
Korea; Rep.,51245707
|
||||
Kosovo,1816200
|
||||
Kuwait,4052584
|
||||
Kyrgyz Republic,6082700
|
||||
Lao PDR,6758353
|
||||
Latvia,1960424
|
||||
Lebanon,6006668
|
||||
Lesotho,2203821
|
||||
Liberia,4613823
|
||||
Libya,6293253
|
||||
Liechtenstein,37666
|
||||
Lithuania,2872298
|
||||
Luxembourg,582972
|
||||
Macao SAR; China,612167
|
||||
Macedonia; FYR,2081206
|
||||
Madagascar,24894551
|
||||
Malawi,18091575
|
||||
Malaysia,31187265
|
||||
Maldives,417492
|
||||
Mali,17994837
|
||||
Malta,436947
|
||||
Marshall Islands,53066
|
||||
Mauritania,4301018
|
||||
Mauritius,1263473
|
||||
Mexico,127540423
|
||||
Micronesia; Fed. Sts.,104937
|
||||
Moldova,3552000
|
||||
Monaco,38499
|
||||
Mongolia,3027398
|
||||
Montenegro,622781
|
||||
Morocco,35276786
|
||||
Mozambique,28829476
|
||||
Myanmar,52885223
|
||||
Namibia,2479713
|
||||
Nauru,13049
|
||||
Nepal,28982771
|
||||
Netherlands,17018408
|
||||
New Caledonia,278000
|
||||
New Zealand,4692700
|
||||
Nicaragua,6149928
|
||||
Niger,20672987
|
||||
Nigeria,185989640
|
||||
Northern Mariana Islands,55023
|
||||
Norway,5232929
|
||||
Oman,4424762
|
||||
Pakistan,193203476
|
||||
Palau,21503
|
||||
Panama,4034119
|
||||
Papua New Guinea,8084991
|
||||
Paraguay,6725308
|
||||
Peru,31773839
|
||||
Philippines,103320222
|
||||
Poland,37948016
|
||||
Portugal,10324611
|
||||
Puerto Rico,3411307
|
||||
Qatar,2569804
|
||||
Romania,19705301
|
||||
Russian Federation,144342396
|
||||
Rwanda,11917508
|
||||
Samoa,195125
|
||||
San Marino,33203
|
||||
Sao Tome and Principe,199910
|
||||
Saudi Arabia,32275687
|
||||
Senegal,15411614
|
||||
Serbia,7057412
|
||||
Seychelles,94677
|
||||
Sierra Leone,7396190
|
||||
Singapore,5607283
|
||||
Sint Maarten (Dutch part),40005
|
||||
Slovak Republic,5428704
|
||||
Slovenia,2064845
|
||||
Solomon Islands,599419
|
||||
Somalia,14317996
|
||||
South Africa,55908865
|
||||
South Sudan,12230730
|
||||
Spain,46443959
|
||||
Sri Lanka,21203000
|
||||
St. Kitts and Nevis,54821
|
||||
St. Lucia,178015
|
||||
St. Martin (French part),31949
|
||||
St. Vincent and the Grenadines,109643
|
||||
Sudan,39578828
|
||||
Suriname,558368
|
||||
Swaziland,1343098
|
||||
Sweden,9903122
|
||||
Switzerland,8372098
|
||||
Syrian Arab Republic,18430453
|
||||
Tajikistan,8734951
|
||||
Tanzania,55572201
|
||||
Thailand,68863514
|
||||
Timor-Leste,1268671
|
||||
Togo,7606374
|
||||
Tonga,107122
|
||||
Trinidad and Tobago,1364962
|
||||
Tunisia,11403248
|
||||
Turkey,79512426
|
||||
Turkmenistan,5662544
|
||||
Turks and Caicos Islands,34900
|
||||
Tuvalu,11097
|
||||
Uganda,41487965
|
||||
Ukraine,45004645
|
||||
United Arab Emirates,9269612
|
||||
United Kingdom,65637239
|
||||
United States,323127513
|
||||
Uruguay,3444006
|
||||
Uzbekistan,31848200
|
||||
Vanuatu,270402
|
||||
Venezuela; RB,31568179
|
||||
Vietnam,92701100
|
||||
Virgin Islands (U.S.),102951
|
||||
West Bank and Gaza,4551566
|
||||
Yemen; Rep.,27584213
|
||||
Zambia,16591390
|
||||
Zimbabwe,16150362
|
||||
|
@@ -1,90 +0,0 @@
|
||||
#include "cmc/hashmap.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "util.c"
|
||||
|
||||
HASHMAP_GENERATE(hm, hmap, , char *, size_t)
|
||||
|
||||
hmap *load(const char *fname);
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
hmap *map = load("data.csv");
|
||||
|
||||
if (!map)
|
||||
return 1;
|
||||
|
||||
printf("+--------------------------------------------------+\n");
|
||||
printf("| Search Country Population by Country Name |\n");
|
||||
printf("| |\n");
|
||||
printf("| - Type 'exit' to exit |\n");
|
||||
printf("| - Type country name to search its population |\n");
|
||||
printf("+--------------------------------------------------+\n\n");
|
||||
|
||||
// If you wish to list all items
|
||||
// char *key;
|
||||
// size_t value, index;
|
||||
|
||||
// hmap_iter iter;
|
||||
// for (hm_iter_new(&iter, map); !hm_iter_end(&iter);)
|
||||
// {
|
||||
// hm_iter_next(&iter, &key, &value, &index);
|
||||
// printf("%30s : %" PRIuMAX "\n", key, value);
|
||||
|
||||
// free(key);
|
||||
// }
|
||||
|
||||
char sbuffer[1000];
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf("Query > ");
|
||||
fflush(stdin);
|
||||
scanf("%[^\n]s", sbuffer);
|
||||
|
||||
if (strcmp(sbuffer, "exit") == 0)
|
||||
break;
|
||||
|
||||
size_t *result = hm_get_ref(map, sbuffer);
|
||||
|
||||
if (result == NULL)
|
||||
printf("Result > %s Not Found\n", sbuffer);
|
||||
else
|
||||
printf("Result > %" PRIuMAX "\n", *result);
|
||||
}
|
||||
|
||||
hm_free(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
hmap *load(const char *fname)
|
||||
{
|
||||
FILE *fptr = fopen(fname, "r");
|
||||
|
||||
if (!fptr)
|
||||
return NULL;
|
||||
|
||||
hmap *map = hm_new(10000, 0.7, chrcmp, chrhash);
|
||||
|
||||
char buff[400];
|
||||
size_t value;
|
||||
|
||||
while (fscanf(fptr, "%[^,],%" PRIuMAX "\n", buff, &value) != EOF)
|
||||
{
|
||||
char *name = strdup(buff);
|
||||
|
||||
if (!hm_insert(map, name, value))
|
||||
{
|
||||
printf("\n\n\nERROR\n");
|
||||
printf("%s : %" PRIuMAX "", name, value);
|
||||
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
int chrcmp(char *a, char *b)
|
||||
{
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
size_t chrhash(char *str)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++))
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 23/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Foreach macro example
|
||||
*/
|
||||
#include "cmc/hashmap.h"
|
||||
#include "utl/foreach.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// Int hash function
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// Generate all the code for the hashmap
|
||||
CMC_GENERATE_HASHMAP(hm, hashmap, int, double)
|
||||
typedef struct hashmap hashmap;
|
||||
typedef struct hashmap_iter hashmap_iter;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Create a new hashmap with custom hash function
|
||||
// The comparison function is only required to know if the key looked for was found
|
||||
hashmap *map = hm_new(1000, 0.6, intcmp, inthash);
|
||||
|
||||
// Add keys mapped to a value
|
||||
for (int i = 0; i < 5000; i++)
|
||||
{
|
||||
hm_insert(map, i, (double)i / 1000.0);
|
||||
}
|
||||
|
||||
// Iterate over the HashMap without the FOR_EACH macro
|
||||
for (hashmap_iter iter = map->it_start(map); !hm_iter_end(&iter); hm_iter_next(&iter))
|
||||
{
|
||||
printf("MAP[%4d] = %.3lf\n", hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
}
|
||||
|
||||
// Iterate over the HashMap using FOR_EACH macro
|
||||
CMC_FOR_EACH(hm, hashmap, map, {
|
||||
// Inside, the variable 'iter' will be available and from it you can access
|
||||
// the key, value or index.
|
||||
printf("MAP[%4d] = %.3lf\n", hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
});
|
||||
|
||||
hm_free(map, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 14/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/hashmap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int hash function
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a hashmap of integers
|
||||
CMC_GENERATE_HASHMAP(hm, hashmap, int, double);
|
||||
typedef struct hashmap hashmap;
|
||||
typedef struct hashmap_iter hashmap_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new hashmap with an initial capacity of 100 and load factor of 0.6
|
||||
hashmap *my_map = hm_new(100, 0.6, intcmp, inthash);
|
||||
|
||||
// Add pairs to the hashmap
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
// Map integers to doubles
|
||||
hm_insert(my_map, i, (double)i / 10.0);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the hashmap
|
||||
for (hashmap_iter it = my_map->it_start(my_map); // Initialize iterator 'it' to the start of the hashmap
|
||||
!hm_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
hm_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = hm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
// Print hashmap
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == hm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = hm_count(my_map) / 2;
|
||||
for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it))
|
||||
{
|
||||
// Access the current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = hm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
// Print hashmap up until limit
|
||||
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the hashmap
|
||||
{
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
break;
|
||||
}
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (hashmap_iter it = my_map->it_end(my_map); // Initialize iterator 'it' to the end of the hashmap
|
||||
!hm_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
hm_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = hm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
// Print hashmap
|
||||
// Note how the conditions for the first and last pairs are simply swapped
|
||||
// Because iterating backwards make the first pair be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first pair
|
||||
if (i == hm_count(my_map) - 1)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == 0)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
hashmap_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the hashmap [ my_map->it_start() and my_map->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_map->it_start(my_map);
|
||||
it = my_map->it_end(my_map);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
hm_iter_init(&it, my_map);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
hashmap_iter *iter = hm_iter_new(my_map);
|
||||
|
||||
// The actual while loop
|
||||
while (!hm_iter_end(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = hm_iter_key(iter);
|
||||
double v = hm_iter_value(iter);
|
||||
size_t i = hm_iter_index(iter);
|
||||
|
||||
// Print index and key value pair
|
||||
printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator forwards
|
||||
hm_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the hashmap
|
||||
hm_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the hashmap
|
||||
hm_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!hm_iter_start(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = hm_iter_key(iter);
|
||||
double v = hm_iter_value(iter);
|
||||
size_t i = hm_iter_index(iter);
|
||||
|
||||
// Print index and the key value pair
|
||||
printf("hashmap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator backwards
|
||||
hm_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the pair
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every value where its key is divisible by 3 to the number 7
|
||||
for (hm_iter_to_start(&it); !hm_iter_end(&it); hm_iter_next(&it))
|
||||
{
|
||||
// Get current key
|
||||
int k = hm_iter_key(&it);
|
||||
|
||||
// Get a reference to the current value
|
||||
double *v = hm_iter_rvalue(&it);
|
||||
|
||||
if (k % 3 == 0)
|
||||
*v = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (hashmap_iter it = my_map->it_start(my_map); !hm_iter_end(&it); hm_iter_next(&it))
|
||||
{
|
||||
int k = hm_iter_key(&it);
|
||||
double v = hm_iter_value(&it);
|
||||
size_t i = hm_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
else if (i == hm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by hm_iter_new()
|
||||
hm_iter_free(iter);
|
||||
// Dispose the hashmap created
|
||||
hm_free(my_map, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Hashset examples
|
||||
|
||||
* iterator.c - A complete example of the hashset iterator
|
||||
* set_ops.c - Demonstrates common set operations like *union*, *intersection*, *difference* and *symmetric difference*.
|
||||
@@ -1,196 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/hashset.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int hash function
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a hashset of integers
|
||||
CMC_GENERATE_HASHSET(hs, hashset, int)
|
||||
typedef struct hashset hashset;
|
||||
typedef struct hashset_iter hashset_iter;
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new hashset with an initial capacity of 100 and load factor of 0.6
|
||||
hashset *my_hashset = hs_new(100, 0.6, intcmp, inthash);
|
||||
|
||||
// Add elements to the hashset
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
hs_insert(my_hashset, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the hashset
|
||||
for (hashset_iter it = my_hashset->it_start(my_hashset); // Initialize iterator 'it' to the start of the hashset
|
||||
!hs_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
hs_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = hs_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = hs_iter_index(&it);
|
||||
|
||||
// Print hashset
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == hs_count(my_hashset) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = hs_count(my_hashset) / 2;
|
||||
for (hashset_iter it = my_hashset->it_start(my_hashset); !hs_iter_end(&it); hs_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = hs_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = hs_iter_index(&it);
|
||||
|
||||
// Print hashset up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the hashset
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (hashset_iter it = my_hashset->it_end(my_hashset); // Initialize iterator 'it' to the end of the hashset
|
||||
!hs_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
hs_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = hs_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = hs_iter_index(&it);
|
||||
|
||||
// Print hashset
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == hs_count(my_hashset) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
hashset_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the hashset [ my_hashset->it_start() and my_hashset->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_hashset->it_start(my_hashset);
|
||||
it = my_hashset->it_end(my_hashset);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
hs_iter_init(&it, my_hashset);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
hashset_iter *iter = hs_iter_new(my_hashset);
|
||||
|
||||
// The actual while loop
|
||||
while (!hs_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = hs_iter_value(iter);
|
||||
size_t i = hs_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("hashset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
hs_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the hashset
|
||||
hs_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the hashset
|
||||
hs_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!hs_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = hs_iter_value(iter);
|
||||
size_t i = hs_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("hashset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
hs_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// In the case of a hashset or any set, this is not possible because the
|
||||
// values of a set are its keys. Changing the elements could cause the set
|
||||
// to be in an invalid state.
|
||||
|
||||
// Dispose the iterator called by hs_iter_new()
|
||||
hs_iter_free(iter);
|
||||
// Dispose the hashset created
|
||||
hs_free(my_hashset, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/**
|
||||
* set_ops.c
|
||||
*
|
||||
* Creation Date: 03/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
// Demonstration of set operations like:
|
||||
// - Union
|
||||
// - Intersection
|
||||
// - Difference
|
||||
// - Symmetric Difference
|
||||
|
||||
#include "cmc/hashset.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
CMC_GENERATE_HASHSET(set, set, int)
|
||||
typedef struct set set;
|
||||
typedef struct set_iter set_iter;
|
||||
|
||||
|
||||
void print_set(set *s)
|
||||
{
|
||||
set_iter iter;
|
||||
set_iter_init(&iter, s);
|
||||
for (set_iter_to_start(&iter); !set_iter_end(&iter); set_iter_next(&iter))
|
||||
{
|
||||
int result = set_iter_value(&iter);
|
||||
size_t index = set_iter_index(&iter);
|
||||
|
||||
if (index == 0)
|
||||
printf("[ %2d, ", result);
|
||||
else if (index == s->count - 1)
|
||||
printf("%2d ]\n", result);
|
||||
else
|
||||
printf("%2d, ", result);
|
||||
}
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
set *set1 = set_new(50, 0.9, intcmp, inthash);
|
||||
set *set2 = set_new(50, 0.9, intcmp, inthash);
|
||||
|
||||
for (int i = 1; i <= 20; i++)
|
||||
set_insert(set1, i);
|
||||
|
||||
for (int i = 11; i <= 30; i++)
|
||||
set_insert(set2, i);
|
||||
|
||||
set *set3 = set_union(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("UNION\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set3);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
set *set4 = set_intersection(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("INTERSECTION\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set4);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
set *set5 = set_difference(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("DIFFERENCE\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set5);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
set *set6 = set_symmetric_difference(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("SYMMETRIC DIFFERENCE\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set6);
|
||||
|
||||
set_free(set1, NULL);
|
||||
set_free(set2, NULL);
|
||||
set_free(set3, NULL);
|
||||
set_free(set4, NULL);
|
||||
set_free(set5, NULL);
|
||||
set_free(set6, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Heap examples
|
||||
|
||||
* heapsort.c - Uses the heap to sort the elements in a given array.
|
||||
* iterator.c - A complete example of the heap iterator
|
||||
@@ -1,58 +0,0 @@
|
||||
/**
|
||||
* heapsort.c
|
||||
*
|
||||
* Creation Date: 25/03/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/heap.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
CMC_GENERATE_HEAP(h, heap, int)
|
||||
typedef struct heap heap;
|
||||
typedef struct heap_iter heap_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
heap *h = h_new(32, cmc_max_heap, intcmp);
|
||||
|
||||
for (int i = 1; i < 101; i++)
|
||||
{
|
||||
h_insert(h, i);
|
||||
}
|
||||
|
||||
size_t S = h_count(h);
|
||||
|
||||
int *buff = malloc(sizeof(int) * S);
|
||||
|
||||
int index = 0;
|
||||
while (!h_empty(h))
|
||||
{
|
||||
int tmp;
|
||||
h_remove(h, &tmp);
|
||||
buff[index++] = tmp;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < S; i++)
|
||||
{
|
||||
if (i == 0)
|
||||
printf("[ %d, ", buff[i]);
|
||||
else if (i == S - 1)
|
||||
printf("%d ]\n", buff[i]);
|
||||
else
|
||||
printf("%d, ", buff[i]);
|
||||
}
|
||||
|
||||
free(buff);
|
||||
h_free(h, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/heap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a heap of integers
|
||||
CMC_GENERATE_HEAP(h, heap, int);
|
||||
typedef struct heap heap;
|
||||
typedef struct heap_iter heap_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new max heap with an initial capacity of 100
|
||||
heap *my_heap = h_new(100, cmc_max_heap, intcmp);
|
||||
|
||||
// Add elements to the heap
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
h_insert(my_heap, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the heap
|
||||
for (heap_iter it = my_heap->it_start(my_heap); // Initialize iterator 'it' to the start of the heap
|
||||
!h_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
h_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = h_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = h_iter_index(&it);
|
||||
|
||||
// Print heap
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == h_count(my_heap) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = h_count(my_heap) / 2;
|
||||
for (heap_iter it = my_heap->it_start(my_heap); !h_iter_end(&it); h_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = h_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = h_iter_index(&it);
|
||||
|
||||
// Print heap up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the heap
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (heap_iter it = my_heap->it_end(my_heap); // Initialize iterator 'it' to the end of the heap
|
||||
!h_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
h_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = h_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = h_iter_index(&it);
|
||||
|
||||
// Print heap
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == h_count(my_heap) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
heap_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the heap [ my_heap->it_start() and my_heap->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_heap->it_start(my_heap);
|
||||
it = my_heap->it_end(my_heap);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
h_iter_init(&it, my_heap);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
heap_iter *iter = h_iter_new(my_heap);
|
||||
|
||||
// The actual while loop
|
||||
while (!h_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = h_iter_value(iter);
|
||||
size_t i = h_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("heap[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
h_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the heap
|
||||
h_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the heap
|
||||
h_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!h_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = h_iter_value(iter);
|
||||
size_t i = h_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("heap[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
h_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// In the case of a heap this is not possible because the heap have its
|
||||
// elements ordered. Changing them could cause the heap to be in an invalid
|
||||
// state.
|
||||
|
||||
// Dispose the iterator called by h_iter_new()
|
||||
h_iter_free(iter);
|
||||
// Dispose the heap created
|
||||
h_free(my_heap, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/**
|
||||
* deque.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/deque.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_DEQUE(d, deque, int);
|
||||
typedef struct deque deque;
|
||||
typedef struct deque_iter deque_iter;
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize deque and add some elements
|
||||
deque *d = d_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
i % 2 == 0 ? d_push_back(d, i) : d_push_front(d, i);
|
||||
}
|
||||
|
||||
// Initialize iterator
|
||||
deque_iter iter;
|
||||
d_iter_init(&iter, d);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!d_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
d_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!d_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
d_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (d_iter_to_start(&iter); !d_iter_end(&iter); d_iter_next(&iter))
|
||||
{
|
||||
printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (d_iter_to_end(&iter); !d_iter_start(&iter); d_iter_prev(&iter))
|
||||
{
|
||||
printf("D[%2d] = %2d\n", d_iter_index(&iter), d_iter_value(&iter));
|
||||
}
|
||||
|
||||
d_free(d, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* hashmap.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/hashmap.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_HASHMAP(hm, hmap, int, double)
|
||||
typedef struct hmap hmap;
|
||||
typedef struct hmap_iter hmap_iter;
|
||||
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
double varr[10] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
|
||||
|
||||
// Initialize hashmap and add some element
|
||||
hmap *hm = hm_new(50, 0.9, intcmp, inthash);
|
||||
for (int i = 0; i < 10; i++)
|
||||
hm_insert(hm, i, varr[i]);
|
||||
|
||||
// Initialize iterator
|
||||
hmap_iter iter;
|
||||
hm_iter_init(&iter, hm);
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!hm_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
hm_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!hm_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
hm_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (hm_iter_to_start(&iter); !hm_iter_end(&iter); hm_iter_next(&iter))
|
||||
{
|
||||
printf("HM[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (hm_iter_to_end(&iter); !hm_iter_start(&iter); hm_iter_prev(&iter))
|
||||
{
|
||||
printf("HM[%2d] = { %2d : %2.2lf }\n", hm_iter_index(&iter), hm_iter_key(&iter), hm_iter_value(&iter));
|
||||
}
|
||||
|
||||
hm_free(hm, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* hashset.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/hashset.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_HASHSET(hs, hset, int);
|
||||
typedef struct hset hset;
|
||||
typedef struct hset_iter hset_iter;
|
||||
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize hashset and add some elements
|
||||
hset *hs = hs_new(10, 0.9, intcmp, inthash);
|
||||
for (int i = 0; i < 10; i++)
|
||||
hs_insert(hs, i);
|
||||
|
||||
// Initialize iterator
|
||||
hset_iter iter;
|
||||
hs_iter_init(&iter, hs);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!hs_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
hs_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!hs_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
hs_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (hs_iter_to_start(&iter); !hs_iter_end(&iter); hs_iter_next(&iter))
|
||||
{
|
||||
printf("HS[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (hs_iter_to_end(&iter); !hs_iter_start(&iter); hs_iter_prev(&iter))
|
||||
{
|
||||
printf("HS[%2d] = %2d\n", hs_iter_index(&iter), hs_iter_value(&iter));
|
||||
}
|
||||
|
||||
hs_free(hs, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* heap.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/heap.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
|
||||
CMC_GENERATE_HEAP(h, heap, int)
|
||||
typedef struct heap heap;
|
||||
typedef struct heap_iter heap_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize heap and add some elements
|
||||
heap *h = h_new(10, cmc_max_heap, intcmp);
|
||||
for (int i = 0; i < 10; i++)
|
||||
h_insert(h, i);
|
||||
|
||||
// Initialize iterator
|
||||
heap_iter iter;
|
||||
h_iter_init(&iter, h);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!h_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
h_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!h_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
h_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (h_iter_to_start(&iter); !h_iter_end(&iter); h_iter_next(&iter))
|
||||
{
|
||||
printf("H[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (h_iter_to_end(&iter); !h_iter_start(&iter); h_iter_prev(&iter))
|
||||
{
|
||||
printf("H[%2d] = %2d\n", h_iter_index(&iter), h_iter_value(&iter));
|
||||
}
|
||||
|
||||
h_free(h, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* linkedlist.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/linkedlist.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_LINKEDLIST(ll, linkedlist, int);
|
||||
typedef struct linkedlist linkedlist;
|
||||
typedef struct linkedlist_iter linkedlist_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize linkedlist and add some elements
|
||||
linkedlist *ll = ll_new();
|
||||
for (int i = 0; i < 10; i++)
|
||||
ll_push_back(ll, i);
|
||||
|
||||
// Initialize iterator
|
||||
linkedlist_iter iter;
|
||||
ll_iter_init(&iter, ll);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!ll_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
ll_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!ll_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
ll_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (ll_iter_to_start(&iter); !ll_iter_end(&iter); ll_iter_next(&iter))
|
||||
{
|
||||
printf("LL[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (ll_iter_to_end(&iter); !ll_iter_start(&iter); ll_iter_prev(&iter))
|
||||
{
|
||||
printf("LL[%2d] = %2d\n", ll_iter_index(&iter), ll_iter_value(&iter));
|
||||
}
|
||||
|
||||
ll_free(ll, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* list.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/list.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_LIST(l, list, int);
|
||||
typedef struct list list;
|
||||
typedef struct list_iter list_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize list and add some elements
|
||||
list *l = l_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
// Initialize iterator
|
||||
list_iter iter;
|
||||
l_iter_init(&iter, l);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!l_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
l_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!l_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
l_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (l_iter_to_start(&iter); !l_iter_end(&iter); l_iter_next(&iter))
|
||||
{
|
||||
printf("L[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (l_iter_to_end(&iter); !l_iter_start(&iter); l_iter_prev(&iter))
|
||||
{
|
||||
printf("L[%2d] = %2d\n", l_iter_index(&iter), l_iter_value(&iter));
|
||||
}
|
||||
|
||||
l_free(l, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* queue.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/queue.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_QUEUE(q, queue, int)
|
||||
typedef struct queue queue;
|
||||
typedef struct queue_iter queue_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize queue and add some elements
|
||||
queue *q = q_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
q_enqueue(q, i);
|
||||
|
||||
// Initialize iterator
|
||||
queue_iter iter;
|
||||
q_iter_init(&iter, q);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!q_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
|
||||
q_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!q_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
|
||||
q_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (q_iter_to_start(&iter); !q_iter_end(&iter); q_iter_next(&iter))
|
||||
{
|
||||
printf("Q[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (q_iter_to_end(&iter); !q_iter_start(&iter); q_iter_prev(&iter))
|
||||
{
|
||||
printf("Q[%2d] = %2d\n", q_iter_index(&iter), q_iter_value(&iter));
|
||||
}
|
||||
|
||||
q_free(q, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* stack.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/stack.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_STACK(s, stack, int)
|
||||
typedef struct stack stack;
|
||||
typedef struct stack_iter stack_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize stack and add some elements
|
||||
stack *s = s_new(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
s_push(s, i);
|
||||
|
||||
// Initialize iterator
|
||||
stack_iter iter;
|
||||
s_iter_init(&iter, s);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!s_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
|
||||
s_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!s_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
|
||||
s_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (s_iter_to_start(&iter); !s_iter_end(&iter); s_iter_next(&iter))
|
||||
{
|
||||
printf("S[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (s_iter_to_end(&iter); !s_iter_start(&iter); s_iter_prev(&iter))
|
||||
{
|
||||
printf("S[%2d] = %2d\n", s_iter_index(&iter), s_iter_value(&iter));
|
||||
}
|
||||
|
||||
s_free(s, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* treemap.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/treemap.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
CMC_GENERATE_TREEMAP(tm, tmap, int, double)
|
||||
typedef struct tmap tmap;
|
||||
typedef struct tmap_iter tmap_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
double varr[10] = {0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};
|
||||
|
||||
// Initialize treemap and add some element
|
||||
tmap *hm = tm_new(intcmp);
|
||||
for (int i = 0; i < 10; i++)
|
||||
tm_insert(hm, i, varr[i]);
|
||||
|
||||
// Initialize iterator
|
||||
tmap_iter iter;
|
||||
tm_iter_init(&iter, hm);
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!tm_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
|
||||
tm_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!tm_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
|
||||
tm_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (tm_iter_to_start(&iter); !tm_iter_end(&iter); tm_iter_next(&iter))
|
||||
{
|
||||
printf("TM[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (tm_iter_to_end(&iter); !tm_iter_start(&iter); tm_iter_prev(&iter))
|
||||
{
|
||||
printf("TM[%2d] = { %2d : %2.2lf }\n", tm_iter_index(&iter), tm_iter_key(&iter), tm_iter_value(&iter));
|
||||
}
|
||||
|
||||
tm_free(hm, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/**
|
||||
* treeset.c
|
||||
*
|
||||
* Creation Date: 11/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/treeset.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
CMC_GENERATE_TREESET(ts, tset, int);
|
||||
typedef struct tset tset;
|
||||
typedef struct tset_iter tset_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize treeset and add some elements
|
||||
tset *ts = ts_new(intcmp);
|
||||
for (int i = 0; i < 10; i++)
|
||||
ts_insert(ts, i);
|
||||
|
||||
// Initialize iterator
|
||||
tset_iter iter;
|
||||
ts_iter_init(&iter, ts);
|
||||
|
||||
// Make the iterator go back and forward
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
while (!ts_iter_end(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
|
||||
ts_iter_next(&iter);
|
||||
}
|
||||
printf("\n");
|
||||
while (!ts_iter_start(&iter))
|
||||
{
|
||||
printf("C[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
|
||||
ts_iter_prev(&iter);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
for (ts_iter_to_start(&iter); !ts_iter_end(&iter); ts_iter_next(&iter))
|
||||
{
|
||||
printf("TS[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
for (ts_iter_to_end(&iter); !ts_iter_start(&iter); ts_iter_prev(&iter))
|
||||
{
|
||||
printf("TS[%2d] = %2d\n", ts_iter_index(&iter), ts_iter_value(&iter));
|
||||
}
|
||||
|
||||
ts_free(ts, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Linkedlist examples
|
||||
|
||||
* iterator.c - A complete example of the linked list iterator
|
||||
* linked_list_node.c - Example of using functions that add or remove elements relative to a node.
|
||||
@@ -1,195 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 10/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/linkedlist.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a linkedlist of integers
|
||||
CMC_GENERATE_LINKEDLIST((ll, linkedlist, int)
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new linkedlist
|
||||
linkedlist *my_linkedlist = ll_new();
|
||||
|
||||
// Add elements to the linkedlist
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
ll_push_back(my_linkedlist, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the linkedlist
|
||||
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); // Initialize iterator 'it' to the start of the linkedlist
|
||||
!ll_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
ll_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = ll_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
// Print linkedlist
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == ll_count(my_linkedlist) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = ll_count(my_linkedlist) / 2;
|
||||
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); !ll_iter_end(&it); ll_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = ll_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
// Print linkedlist up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the linkedlist
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (linkedlist_iter it = my_linkedlist->it_end(my_linkedlist); // Initialize iterator 'it' to the end of the linkedlist
|
||||
!ll_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
ll_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = ll_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
// Print linkedlist
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == ll_count(my_linkedlist) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
linkedlist_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the linkedlist [ my_linkedlist->it_start() and my_linkedlist->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_linkedlist->it_start(my_linkedlist);
|
||||
it = my_linkedlist->it_end(my_linkedlist);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
ll_iter_init(&it, my_linkedlist);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
linkedlist_iter *iter = ll_iter_new(my_linkedlist);
|
||||
|
||||
// The actual while loop
|
||||
while (!ll_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ll_iter_value(iter);
|
||||
size_t i = ll_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("linkedlist[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
ll_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the linkedlist
|
||||
ll_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the linkedlist
|
||||
ll_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!ll_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ll_iter_value(iter);
|
||||
size_t i = ll_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("linkedlist[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
ll_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 2 to the number 7
|
||||
for (ll_iter_to_start(&it); !ll_iter_end(&it); ll_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = ll_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 2 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (linkedlist_iter it = my_linkedlist->it_start(my_linkedlist); !ll_iter_end(&it); ll_iter_next(&it))
|
||||
{
|
||||
int e = ll_iter_value(&it);
|
||||
size_t i = ll_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == ll_count(my_linkedlist) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by ll_iter_new()
|
||||
ll_iter_free(iter);
|
||||
// Dispose the linkedlist created
|
||||
ll_free(my_linkedlist);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* linked_list_node.c
|
||||
*
|
||||
* Creation Date: 26/03/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/linkedlist.h"
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
CMC_GENERATE_LINKEDLIST((l, list, int)
|
||||
|
||||
int main(void)
|
||||
{
|
||||
list *l = l_new();
|
||||
|
||||
for (int i = 0; i < 97; i++)
|
||||
l_push_back(l, i);
|
||||
|
||||
// Add 99 after and 33 before every node where its data is divisible by 3
|
||||
for (list_node *node = l->head; node != NULL; node = node->next)
|
||||
{
|
||||
if (node->data % 3 == 0)
|
||||
{
|
||||
l_insert_before(l, node, 33);
|
||||
l_insert_after(l, node, 99);
|
||||
node = node->next; // skip 99
|
||||
}
|
||||
}
|
||||
|
||||
size_t s = 0;
|
||||
for (list_node *node = l_head(l); node != NULL; node = l_next_node(node), s++)
|
||||
{
|
||||
if (node->prev == NULL)
|
||||
printf("[ %d, ", node->data);
|
||||
else if (node->next == NULL)
|
||||
printf("%d ]\n", node->data);
|
||||
else
|
||||
printf("%d, ", node->data);
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
s = 0;
|
||||
for (list_node *node = l_tail(l); node != NULL; node = l_prev_node(node), s++)
|
||||
{
|
||||
if (node->next == NULL)
|
||||
printf("[ %d, ", node->data);
|
||||
else if (node->prev == NULL)
|
||||
printf("%d ]\n", node->data);
|
||||
else
|
||||
printf("%d, ", node->data);
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
printf("List Head: %d\nList Tail: %d\nList Count: %" PRIuMAX "\n", l->head->data, l->tail->data, l->count);
|
||||
|
||||
assert(s == l->count);
|
||||
|
||||
l_free(l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
# List examples
|
||||
|
||||
* iterator.c - A complete example of the list iterator
|
||||
* list.c - Example of using a list and its iterator.
|
||||
* string.c - How to treat a list as a mutable string.
|
||||
@@ -1,198 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 10/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/list.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a list of integers
|
||||
CMC_GENERATE_LIST(l, list, int);
|
||||
typedef struct list list;
|
||||
typedef struct list_iter list_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new list with an initial capacity of 100
|
||||
list *my_list = l_new(100);
|
||||
|
||||
// Add elements to the list
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
l_push_back(my_list, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the list
|
||||
for (list_iter it = my_list->it_start(my_list); // Initialize iterator 'it' to the start of the list
|
||||
!l_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
l_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = l_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
// Print list
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == l_count(my_list) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = l_count(my_list) / 2;
|
||||
for (list_iter it = my_list->it_start(my_list); !l_iter_end(&it); l_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = l_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
// Print list up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the list
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (list_iter it = my_list->it_end(my_list); // Initialize iterator 'it' to the end of the list
|
||||
!l_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
l_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = l_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
// Print list
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == l_count(my_list) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
list_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the list [ my_list->it_start() and my_list->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_list->it_start(my_list);
|
||||
it = my_list->it_end(my_list);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
l_iter_init(&it, my_list);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
list_iter *iter = l_iter_new(my_list);
|
||||
|
||||
// The actual while loop
|
||||
while (!l_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = l_iter_value(iter);
|
||||
size_t i = l_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("list[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
l_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the list
|
||||
l_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the list
|
||||
l_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!l_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = l_iter_value(iter);
|
||||
size_t i = l_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("list[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
l_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 2 to the number 7
|
||||
for (l_iter_to_start(&it); !l_iter_end(&it); l_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = l_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 2 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (list_iter it = my_list->it_start(my_list); !l_iter_end(&it); l_iter_next(&it))
|
||||
{
|
||||
int e = l_iter_value(&it);
|
||||
size_t i = l_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == l_count(my_list) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by l_iter_new()
|
||||
l_iter_free(iter);
|
||||
// Dispose the list created
|
||||
l_free(my_list, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/**
|
||||
* list.c
|
||||
*
|
||||
* Creation Date: 08/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/list.h"
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_LIST(l, list, int);
|
||||
typedef struct list list;
|
||||
typedef struct list_iter list_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a list with internal capacity of 100
|
||||
list *my_list = l_new(100);
|
||||
|
||||
// - push_front (index: 0) [Complexity: O(N)]
|
||||
// - push (index: give) [Complexity: O(N)*]
|
||||
// - push_back (index: count) [Complexity: O(1)]
|
||||
//
|
||||
// - pop_front (index: 0) [Complexity: O(N)]
|
||||
// - pop (index: given) [Complexity: O(N)*]
|
||||
// - push_back (index: count - 1) [Complexity: O(1)]
|
||||
//
|
||||
// *average
|
||||
//
|
||||
// Average list Input/Output: O(N)
|
||||
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
// Add elements to the list
|
||||
l_push_back(my_list, i);
|
||||
}
|
||||
|
||||
// Erase all values from the list
|
||||
l_clear(my_list, NULL);
|
||||
|
||||
// Now that list is empty, add only even numbers
|
||||
for (int i = 0; i < 200; i++)
|
||||
{
|
||||
// Add even numbers to a given index. In this case they are being added
|
||||
// to the end of the list (count index == push_back). With a condition
|
||||
// of being even (i % 2 == 0)
|
||||
if (i % 2 == 0) l_push_back(my_list, i);
|
||||
|
||||
// If added is true, the element was added to the list
|
||||
}
|
||||
|
||||
// Iterator
|
||||
list_iter iter;
|
||||
int result, sum = 0;
|
||||
size_t index;
|
||||
|
||||
// Iterate over each element starting from the start (iter_new positions
|
||||
// the iterator to the start of the list) until the end of the list.
|
||||
for (l_iter_init(&iter, my_list); !l_iter_end(&iter); l_iter_next(&iter))
|
||||
{
|
||||
// Here index corresponds to the position of the result relative to all
|
||||
// other elements in the iteration. It is only a coincidence that the
|
||||
// index here is the same as the result's position in the list.
|
||||
index = l_iter_index(&iter);
|
||||
result = l_iter_value(&iter);
|
||||
|
||||
// Do whatever you want with result and index, e.g.
|
||||
sum += result * index;
|
||||
}
|
||||
|
||||
// Release resources
|
||||
l_free(my_list, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/**
|
||||
* string.c
|
||||
*
|
||||
* Creation Date: 08/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/list.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
CMC_GENERATE_LIST(str, string, char);
|
||||
typedef struct string string;
|
||||
typedef struct string_iter string_iter;
|
||||
|
||||
|
||||
// Comparison function
|
||||
int chrcmp(char a, char b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
void print_str(string *str)
|
||||
{
|
||||
// If the buffer is not completely filled, there will be at least one null
|
||||
// byte in the end of the list's contents. This printf is possible but very
|
||||
// dangerous as you might end up printing something else from memory until
|
||||
// a null byte.
|
||||
printf("%s\n", str->buffer);
|
||||
|
||||
printf("Size: %llu\n", str_count(str));
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// How to treat a list as a mutable string without \0 at the end
|
||||
char *example1 = "Lorem ipsum";
|
||||
char *example2 = "dolor sit amet";
|
||||
char *example3 = "consectetur";
|
||||
|
||||
string *my_str = str_new_from(example2, strlen(example2));
|
||||
|
||||
// Add a single character to the front of the list
|
||||
str_push_front(my_str, ' ');
|
||||
|
||||
// Add a sequence of characters to the front of the list
|
||||
str_seq_push_front(my_str, example1, strlen(example1));
|
||||
|
||||
// Add a charater to the back of the list
|
||||
str_push_back(my_str, ' ');
|
||||
|
||||
// Add a sequence of characters to the back of the list
|
||||
str_seq_push_back(my_str, example3, strlen(example3));
|
||||
|
||||
// Iterate through each letter and print it
|
||||
string_iter iter;
|
||||
str_iter_init(&iter, my_str);
|
||||
size_t index;
|
||||
char result;
|
||||
|
||||
// Printing each character
|
||||
for (str_iter_to_start(&iter); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
// You can also print it reversed
|
||||
for (str_iter_to_end(&iter); !str_iter_start(&iter); str_iter_prev(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
// Now remove the first letter supposing we don't know where it starts
|
||||
index = str_indexof(my_str, ' ', chrcmp, true);
|
||||
|
||||
if (index == str_count(my_str))
|
||||
{
|
||||
// char not found...
|
||||
// Treat error
|
||||
}
|
||||
|
||||
// Now that we know where the first word is, remove it, including the
|
||||
// extra space. [from, to] are inclusive.
|
||||
str_seq_pop_at(my_str, 0, index);
|
||||
|
||||
// Print it once again
|
||||
for (str_iter_to_start(&iter); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\nString length: %lu\n\n", str_count(my_str));
|
||||
|
||||
print_str(my_str);
|
||||
|
||||
// Removing last word.
|
||||
// Finding last white space:
|
||||
index = str_indexof(my_str, ' ', chrcmp, false);
|
||||
|
||||
// Extract last word including white space
|
||||
string *str_out = str_seq_sublist(my_str, index, str_count(my_str) - 1);
|
||||
|
||||
if (!str_out)
|
||||
printf("Could not extract string\n");
|
||||
else
|
||||
{
|
||||
// Pop white space
|
||||
str_pop_front(str_out);
|
||||
|
||||
for (str_iter_init(&iter, my_str); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\nString length: %lu\n\n", str_count(my_str));
|
||||
|
||||
for (str_iter_init(&iter, str_out); !str_iter_end(&iter); str_iter_next(&iter))
|
||||
{
|
||||
putchar(str_iter_value(&iter));
|
||||
}
|
||||
|
||||
printf("\nString length: %lu\n", str_count(str_out));
|
||||
}
|
||||
|
||||
// Free strings
|
||||
str_free(my_str, NULL);
|
||||
str_free(str_out, NULL);
|
||||
|
||||
printf("\n----------------------------------------\n\n");
|
||||
|
||||
// Another example follows
|
||||
// Using prepend, insert, append, remove and extract functions
|
||||
string *str = str_new(100);
|
||||
|
||||
str_seq_push_front(str, "Hello World!", 12);
|
||||
|
||||
print_str(str);
|
||||
|
||||
str_seq_push_at(str, "Awesome ", 8, 6);
|
||||
|
||||
print_str(str);
|
||||
|
||||
str_seq_push_back(str, " Indigo.", 8);
|
||||
|
||||
print_str(str);
|
||||
|
||||
str_seq_pop_at(str, 14, 20);
|
||||
|
||||
print_str(str);
|
||||
|
||||
string *str_res = str_seq_sublist(str, 5, 12);
|
||||
|
||||
print_str(str);
|
||||
print_str(str_res);
|
||||
|
||||
str_free(str, NULL);
|
||||
str_free(str_res, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Multimap examples
|
||||
|
||||
* multimap.c - Basic examples of a multimap.
|
||||
@@ -1,89 +0,0 @@
|
||||
#include "cmc/multimap.h"
|
||||
#include "utl/foreach.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
CMC_GENERATE_MULTIMAP(mm, multi_map, int, int);
|
||||
typedef struct multi_map multi_map;
|
||||
typedef struct multi_map_iter multi_map_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
const int min = 1, max = 201;
|
||||
multi_map *map = mm_new(50, 0.8, intcmp, inthash);
|
||||
|
||||
printf("Multimap actual capacity: %" PRIu64 "\n", map->capacity);
|
||||
printf("Adding items from %d to %d twice\n", min, max);
|
||||
|
||||
for (int i = min; i < max; i++)
|
||||
if (!mm_insert(map, i, i))
|
||||
printf("ERROR with %d:%d\n", i, i);
|
||||
|
||||
for (int i = min; i < max; i++)
|
||||
if (!mm_insert(map, i, i))
|
||||
printf("ERROR with %d:%d\n", i, i);
|
||||
|
||||
printf("Multimap count : %" PRIu64 "\n", map->count);
|
||||
printf("Multimap capacity : %" PRIu64 "\n", map->capacity);
|
||||
printf("Multimap load : %lf\n", (double)map->count / (double)map->capacity);
|
||||
|
||||
int64_t sum = 0;
|
||||
|
||||
for (int i = min; i < max; i++)
|
||||
sum += mm_get(map, i);
|
||||
|
||||
printf("Sum (unique): %" PRId64 "\n", sum);
|
||||
|
||||
CMC_FOR_EACH(mm, multi_map, map, {
|
||||
printf(
|
||||
"[%3" PRIu64 "] = { %3d : %3d }\n",
|
||||
iter.index,
|
||||
iter.curr_entry->key,
|
||||
iter.curr_entry->value
|
||||
);
|
||||
});
|
||||
|
||||
printf("Removing all items\n");
|
||||
|
||||
for (int i = min; i < max; i++)
|
||||
if (!mm_remove_all(map, i, NULL))
|
||||
printf("ERROR with %d:%d\n", i, i);
|
||||
|
||||
sum = 0;
|
||||
|
||||
for (int i = min; i < max; i++)
|
||||
sum += mm_get(map, i);
|
||||
|
||||
printf("Sum: %" PRId64 "\n", sum);
|
||||
|
||||
CMC_FOR_EACH(mm, multi_map, map, {
|
||||
printf("[%2" PRIu64 "] = { %2d : %5d }\n",
|
||||
iter.index,
|
||||
iter.curr_entry->key,
|
||||
iter.curr_entry->value
|
||||
);
|
||||
});
|
||||
|
||||
mm_free(map, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# Multiset examples
|
||||
|
||||
* multiset_operations.c - Demonstrates common multiset operations.
|
||||
@@ -1,122 +0,0 @@
|
||||
/**
|
||||
* multiset_operations.c
|
||||
*
|
||||
* Creation Date: 01/08/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include <cmc/multiset.h>
|
||||
#include <utl/assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
CMC_GENERATE_MULTISET(ms, multiset, char);
|
||||
typedef struct multiset multiset;
|
||||
typedef struct multiset_iter multiset_iter;
|
||||
|
||||
|
||||
struct pair
|
||||
{
|
||||
char value;
|
||||
size_t mul;
|
||||
};
|
||||
|
||||
int charcmp(char a, char b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
size_t charhash(char a)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
void print_set(multiset *M)
|
||||
{
|
||||
cmc_assert_not_equals(ptr, NULL, M);
|
||||
|
||||
size_t S = ms_count(M);
|
||||
|
||||
printf("%s : ", ms_to_string(M).s);
|
||||
|
||||
if (S == 0)
|
||||
{
|
||||
printf("{ EMPTY SET }\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (multiset_iter it = M->it_start(M); !ms_iter_end(&it); ms_iter_next(&it))
|
||||
{
|
||||
size_t index = ms_iter_index(&it);
|
||||
char value = ms_iter_value(&it);
|
||||
size_t mul = ms_iter_multiplicity(&it);
|
||||
|
||||
if (index == 0)
|
||||
printf("{ %c:%" PRIuMAX ", ", value, mul);
|
||||
else if (index == S - 1)
|
||||
printf("%c:%" PRIuMAX " }\n", value, mul);
|
||||
else
|
||||
printf("%c:%" PRIuMAX ", ", value, mul);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
struct pair mset1[4] = {{'a', 2}, {'b', 1}, {'c', 3}, {'d', 1}};
|
||||
struct pair mset2[4] = {{'c', 1}, {'d', 3}, {'e', 1}, {'f', 2}};
|
||||
|
||||
multiset *A = ms_new(20, 0.6, charcmp, charhash);
|
||||
multiset *B = ms_new(20, 0.6, charcmp, charhash);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
cmc_assert(ms_insert_many(A, mset1[i].value, mset1[i].mul));
|
||||
cmc_assert(ms_insert_many(B, mset2[i].value, mset2[i].mul));
|
||||
}
|
||||
|
||||
printf("Given two sets A and B:\n");
|
||||
print_set(A);
|
||||
print_set(B);
|
||||
|
||||
multiset *U = ms_union(A, B);
|
||||
printf("\nA UNION B:\n");
|
||||
print_set(U);
|
||||
|
||||
multiset *I = ms_intersection(A, B);
|
||||
printf("\nA INTERSECTION B:\n");
|
||||
print_set(I);
|
||||
|
||||
multiset *DA = ms_difference(A, B);
|
||||
multiset *DB = ms_difference(B, A);
|
||||
printf("\nA - B:\n");
|
||||
print_set(DA);
|
||||
printf("\nB - A:\n");
|
||||
print_set(DB);
|
||||
|
||||
multiset *AB = ms_summation(A, B);
|
||||
printf("\nA + B:\n");
|
||||
print_set(AB);
|
||||
|
||||
multiset *BA = ms_summation(B, A);
|
||||
printf("\nB + A:\n");
|
||||
print_set(BA);
|
||||
|
||||
multiset *SD = ms_symmetric_difference(A, B);
|
||||
printf("\nA SYM DIFF B:\n");
|
||||
print_set(SD);
|
||||
|
||||
ms_free(A, NULL);
|
||||
ms_free(B, NULL);
|
||||
ms_free(U, NULL);
|
||||
ms_free(I, NULL);
|
||||
ms_free(DA, NULL);
|
||||
ms_free(DB, NULL);
|
||||
ms_free(AB, NULL);
|
||||
ms_free(BA, NULL);
|
||||
ms_free(SD, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
# Other examples
|
||||
|
||||
* book_store - A book store where its books are loaded onto a list from a csv file. The newly added ones go to a queue of featured books where old ones are removed to give place to new ones. You can find a book by looking up its ISBN using a treemap or traversing the treemap and find all ISBNs of a corresponding title.
|
||||
* separate_header_source - Example of how to compile the header and source separately.
|
||||
* for_each.c - Using the `FOR_EACH` macro.
|
||||
@@ -1,14 +0,0 @@
|
||||
// Separated file for all book functions
|
||||
typedef struct book
|
||||
{
|
||||
int isbn;
|
||||
char *name;
|
||||
} book;
|
||||
|
||||
book *new_book(int isbn, const char *name)
|
||||
{
|
||||
book *b = malloc(sizeof(book));
|
||||
b->isbn = isbn;
|
||||
b->name = strdup(name);
|
||||
return b;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,180 +0,0 @@
|
||||
// Welcome to the book store
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "macro_collections.h"
|
||||
#include "book.c"
|
||||
#include "random.c"
|
||||
|
||||
COLLECTION_GENERATE(LIST, l, list, , , book *)
|
||||
COLLECTION_GENERATE(LIST, il, intlist, , , int)
|
||||
COLLECTION_GENERATE(QUEUE, q, queue, , , book *)
|
||||
COLLECTION_GENERATE(TREEMAP, map, map, , int, char *)
|
||||
COLLECTION_GENERATE(TREESET, set, set, , , char *)
|
||||
|
||||
list *load(void);
|
||||
void shuffle(list *l);
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int chrcmp(char *a, char *b)
|
||||
{
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
srand((unsigned)time(NULL));
|
||||
|
||||
// Load our books from database (csv).
|
||||
list *books = load();
|
||||
|
||||
// Shuffle our books.
|
||||
shuffle(books);
|
||||
|
||||
// Last added books are kept here. These are the 'featured' books.
|
||||
queue *shelf = q_new(10);
|
||||
|
||||
// Books in our library. Using this to fast lookup our books.
|
||||
map *library = map_new(intcmp);
|
||||
|
||||
// Calculate how many unique book titles
|
||||
set *counter = set_new(chrcmp);
|
||||
|
||||
// Add everything to its place.
|
||||
FOR_EACH(l, list, books, {
|
||||
book *value = l_iter_value(&iter);
|
||||
|
||||
// Keep the last added elements
|
||||
if (q_count(shelf) > 7)
|
||||
{
|
||||
q_dequeue(shelf);
|
||||
}
|
||||
|
||||
q_enqueue(shelf, value);
|
||||
|
||||
map_insert(library, value->isbn, value->name);
|
||||
set_insert(counter, value->name);
|
||||
});
|
||||
|
||||
printf("Library Size: %d\n", map_count(library));
|
||||
printf("Unique book titles: %d\n\n", set_count(counter));
|
||||
printf("Showcase Books:\n");
|
||||
FOR_EACH(q, queue, shelf, {
|
||||
book *value = q_iter_value(&iter);
|
||||
printf("[ %d : %-45s ]\n", value->isbn, value->name);
|
||||
});
|
||||
printf("\n");
|
||||
|
||||
set_free(counter);
|
||||
|
||||
int c, isbn;
|
||||
char buffer[100];
|
||||
while (true)
|
||||
{
|
||||
printf("\n[0] [ Exit ]\n");
|
||||
printf("[1] [ Search by ISBN ]\n");
|
||||
printf("[2] [ Search by Name ]\n");
|
||||
printf("> ");
|
||||
scanf("%d", &c);
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
if (c == 1)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
printf("[0] [ Exit ]\n");
|
||||
printf("ISBN:\n> ");
|
||||
scanf("%d", &isbn);
|
||||
|
||||
if (isbn == 0)
|
||||
break;
|
||||
|
||||
char *search = map_get(library, isbn);
|
||||
|
||||
if (search == NULL)
|
||||
printf("No book found\n");
|
||||
else
|
||||
printf("%s\n", search);
|
||||
}
|
||||
}
|
||||
else if (c == 2)
|
||||
{
|
||||
printf("Name:\n> ");
|
||||
fflush(stdin);
|
||||
fgets(buffer, 100, stdin);
|
||||
// Remove newline character
|
||||
buffer[strcspn(buffer, "\n")] = 0;
|
||||
|
||||
intlist *search_list = il_new(32);
|
||||
|
||||
FOR_EACH(map, map, library, {
|
||||
int key = map_iter_key(&iter);
|
||||
char *value = map_iter_value(&iter);
|
||||
|
||||
if (chrcmp(buffer, value) == 0)
|
||||
il_push_back(search_list, key);
|
||||
});
|
||||
|
||||
FOR_EACH(il, intlist, search_list, {
|
||||
printf("[ %d ]\n", il_iter_value(&iter));
|
||||
});
|
||||
|
||||
il_free(search_list);
|
||||
}
|
||||
}
|
||||
|
||||
// Free all memory used by struct book
|
||||
FOR_EACH(l, list, books, {
|
||||
book *b = l_iter_value(&iter);
|
||||
|
||||
if (b)
|
||||
free(b->name);
|
||||
|
||||
free(b);
|
||||
});
|
||||
|
||||
l_free(books);
|
||||
q_free(shelf);
|
||||
map_free(library);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
list *load(void)
|
||||
{
|
||||
FILE *fptr = fopen("books.csv", "r");
|
||||
|
||||
int isbn;
|
||||
char buffer[1000];
|
||||
list *books = l_new(1000);
|
||||
|
||||
while (fscanf(fptr, "%d,%[^\n\r]s", &isbn, buffer) != EOF)
|
||||
{
|
||||
book *b = new_book(isbn, buffer);
|
||||
l_push_back(books, b);
|
||||
}
|
||||
|
||||
return books;
|
||||
}
|
||||
|
||||
void shuffle(list *l)
|
||||
{
|
||||
size_t min = 0, max = l_count(l) - 1;
|
||||
|
||||
for (size_t i = 0; i < max; i++)
|
||||
{
|
||||
size_t j = randsize(min, max);
|
||||
book *tmp = l->buffer[j];
|
||||
l->buffer[j] = l->buffer[i];
|
||||
l->buffer[i] = tmp;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
// Random functions
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
double rrandom()
|
||||
{
|
||||
return (double)rand() / ((double)RAND_MAX + 1.0);
|
||||
}
|
||||
|
||||
int randint(int min, int max)
|
||||
{
|
||||
return (int)floor(rrandom() * ((double)max - (double)min + 1.0) + (double)min);
|
||||
}
|
||||
|
||||
size_t randsize(size_t min, size_t max)
|
||||
{
|
||||
return (size_t)floor(rrandom() * ((double)max - (double)min + 1.0) + (double)min);
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
#include "macro_collections.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Create containers to use only in this file
|
||||
CMC_GENERATE_LIST(l, list, int)
|
||||
CMC_GENERATE_LINKEDLIST(ll, llist, int)
|
||||
CMC_GENERATE_STACK(s, stack, int)
|
||||
CMC_GENERATE_QUEUE(q, queue, int)
|
||||
CMC_GENERATE_DEQUE(d, deque, int)
|
||||
CMC_GENERATE_TREESET(ts, tset, int)
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Initialize all of them with an internal capacity of 100
|
||||
struct list *l = l_new(100);
|
||||
struct llist *ll = ll_new();
|
||||
struct stack *s = s_new(100);
|
||||
struct queue *q = q_new(100);
|
||||
struct deque *d = d_new(100);
|
||||
struct tset *ts = ts_new(intcmp);
|
||||
|
||||
// Add 20 elements to each of them
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
l_push_back(l, i);
|
||||
ll_push_back(ll, i);
|
||||
s_push(s, i);
|
||||
q_enqueue(q, i);
|
||||
d_push_back(d, i);
|
||||
ts_insert(ts, i);
|
||||
}
|
||||
|
||||
// Some extra elements
|
||||
s_push(s, 21);
|
||||
q_enqueue(q, 21);
|
||||
q_enqueue(q, 22);
|
||||
d_push_back(d, 21);
|
||||
d_push_back(d, 22);
|
||||
d_push_back(d, 23);
|
||||
ll_push_back(ll, 21);
|
||||
ll_push_back(ll, 22);
|
||||
ll_push_back(ll, 23);
|
||||
ll_push_back(ll, 24);
|
||||
ts_insert(ts, 21);
|
||||
ts_insert(ts, 22);
|
||||
ts_insert(ts, 23);
|
||||
ts_insert(ts, 24);
|
||||
ts_insert(ts, 25);
|
||||
|
||||
// All CMC_FOR_EACH macros contains three available variables:
|
||||
// - value : the elements that changes with each iteration
|
||||
// - index : iteration index (first iteration is 0 and last is count - 1)
|
||||
// - iter : iterator struct
|
||||
CMC_FOR_EACH(l, list, l, {
|
||||
int value = l_iter_value(&iter);
|
||||
size_t index = l_iter_index(&iter);
|
||||
if (index == 0)
|
||||
printf("[ %d, ", value);
|
||||
else if (index == iter.target->count - 1)
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH(s, stack, s, {
|
||||
int value = s_iter_value(&iter);
|
||||
size_t index = s_iter_index(&iter);
|
||||
if (index == 0)
|
||||
printf("[ %d, ", value);
|
||||
else if (index == iter.target->count - 1)
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH(q, queue, q, {
|
||||
int value = q_iter_value(&iter);
|
||||
size_t index = q_iter_index(&iter);
|
||||
if (index == 0)
|
||||
printf("[ %d, ", value);
|
||||
else if (index == iter.target->count - 1)
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH(d, deque, d, {
|
||||
int value = d_iter_value(&iter);
|
||||
size_t index = d_iter_index(&iter);
|
||||
if (index == 0)
|
||||
printf("[ %d, ", value);
|
||||
else if (index == iter.target->count - 1)
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH(ll, llist, ll, {
|
||||
int value = ll_iter_value(&iter);
|
||||
size_t index = ll_iter_index(&iter);
|
||||
if (index == 0)
|
||||
printf("[ %d, ", value);
|
||||
else if (index == iter.target->count - 1)
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
});
|
||||
|
||||
CMC_FOR_EACH(ts, tset, ts, {
|
||||
int value = ts_iter_value(&iter);
|
||||
size_t index = ts_iter_index(&iter);
|
||||
if (index == 0)
|
||||
printf("[ %d, ", value);
|
||||
else if (index == iter.target->count - 1)
|
||||
printf("%d ]\n", value);
|
||||
else
|
||||
printf("%d, ", value);
|
||||
});
|
||||
|
||||
l_free(l, NULL);
|
||||
ll_free(ll, NULL);
|
||||
s_free(s, NULL);
|
||||
q_free(q, NULL);
|
||||
d_free(d, NULL);
|
||||
ts_free(ts, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra
|
||||
INCLUDE = ./
|
||||
SRC = ../../../src
|
||||
|
||||
main.exe: containers.o main.o $(SRC)/macro_collections.h
|
||||
$(CC) $^ -o $@
|
||||
|
||||
%.o: %.c $(SRC)/macro_collections.h
|
||||
$(CC) -I $(INCLUDE) -I $(SRC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
run: main.exe $(SRC)/macro_collections.h
|
||||
./main.exe
|
||||
@@ -1,6 +0,0 @@
|
||||
#include "containers.h"
|
||||
|
||||
CMC_GENERATE_LIST_SOURCE(il, int_list, int)
|
||||
CMC_GENERATE_STACK_SOURCE(cs, char_stack, char)
|
||||
CMC_GENERATE_QUEUE_SOURCE(queue, index_queue, size_t)
|
||||
CMC_GENERATE_DEQUE_SOURCE(dq, deque, int)
|
||||
@@ -1,14 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "cmc/list.h"
|
||||
#include "cmc/stack.h"
|
||||
#include "cmc/queue.h"
|
||||
#include "cmc/deque.h"
|
||||
|
||||
|
||||
CMC_GENERATE_LIST_HEADER(il, int_list, int)
|
||||
CMC_GENERATE_STACK_HEADER(cs, char_stack, char)
|
||||
CMC_GENERATE_QUEUE_HEADER(queue, index_queue, size_t)
|
||||
CMC_GENERATE_DEQUE_HEADER(dq, deque, int)
|
||||
@@ -1,264 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "macro_collections.h"
|
||||
#include "containers.h"
|
||||
|
||||
double rrandom()
|
||||
{
|
||||
return (double)rand() / ((double)RAND_MAX + 1.0);
|
||||
}
|
||||
|
||||
int8_t random_int8_t(int8_t min, int8_t max)
|
||||
{
|
||||
return (int8_t)floor(rrandom() * ((double)max - (double)min + 1.0) + (double)min);
|
||||
}
|
||||
|
||||
size_t random_size_t(size_t min, size_t max)
|
||||
{
|
||||
return (size_t)floor(rrandom() * ((double)max - (double)min + 1.0) + (double)min);
|
||||
}
|
||||
|
||||
char random_alpha()
|
||||
{
|
||||
const char alpha[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
|
||||
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z'};
|
||||
return alpha[random_int8_t(0, 61)];
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
srand((unsigned)time(NULL));
|
||||
|
||||
struct int_list *list = il_new(10);
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
il_push_at(list, i, list->count == 0 ? list->count : i % list->count);
|
||||
}
|
||||
|
||||
printf("\n[ ");
|
||||
|
||||
for (size_t i = 0; i < list->count - 1; i++)
|
||||
printf("%d, ", il_get(list, i));
|
||||
|
||||
printf("%d ]\n", il_get(list, list->count - 1));
|
||||
|
||||
il_free(list, NULL);
|
||||
|
||||
list = il_new(10);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
// Add elements
|
||||
il_push_back(list, i);
|
||||
|
||||
// Print
|
||||
if (!il_empty(list))
|
||||
{
|
||||
// Print
|
||||
printf("\n[ ");
|
||||
for (size_t i = 0; i < list->count - 1; i++)
|
||||
{
|
||||
printf("%d, ", il_get(list, i));
|
||||
}
|
||||
printf("%d ]\n", il_get(list, list->count - 1));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
// Remove elements
|
||||
il_pop_back(list);
|
||||
|
||||
if (!il_empty(list))
|
||||
{
|
||||
// Print
|
||||
printf("\n[ ");
|
||||
for (size_t i = 0; i < list->count - 1; i++)
|
||||
{
|
||||
printf("%d, ", il_get(list, i));
|
||||
}
|
||||
printf("%d ]\n", il_get(list, list->count - 1));
|
||||
}
|
||||
}
|
||||
|
||||
il_free(list, NULL);
|
||||
|
||||
list = il_new(1000);
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
if (i % 2 == 0) il_push_at(list, i, list->count);
|
||||
}
|
||||
|
||||
// Print all even numbers
|
||||
if (!il_empty(list))
|
||||
{
|
||||
// Print
|
||||
printf("\n[ ");
|
||||
for (size_t i = 0; i < list->count - 1; i++)
|
||||
{
|
||||
printf("%d, ", il_get(list, i));
|
||||
}
|
||||
printf("%d ]\n", il_get(list, list->count - 1));
|
||||
}
|
||||
|
||||
il_free(list, NULL);
|
||||
|
||||
struct char_stack *stack = cs_new(100);
|
||||
|
||||
for (int i = 0; i < 2000; i++)
|
||||
{
|
||||
cs_push(stack, random_alpha());
|
||||
}
|
||||
|
||||
size_t s = cs_count(stack);
|
||||
size_t c = cs_capacity(stack);
|
||||
printf("Stack size : %" PRIu64 "\n", s);
|
||||
printf("Stack capacity : %" PRIu64 "\n", c);
|
||||
|
||||
for (size_t i = 0; i < s; i++)
|
||||
{
|
||||
printf("%c ", cs_top(stack));
|
||||
cs_pop(stack);
|
||||
}
|
||||
|
||||
printf("\nStack size: %" PRIu64 "", cs_count(stack));
|
||||
printf("\nStack capacity : %" PRIu64 "\n", cs_capacity(stack));
|
||||
|
||||
cs_free(stack, NULL);
|
||||
|
||||
struct index_queue *idxs = queue_new(100);
|
||||
|
||||
size_t sum0 = 0, sum1 = 0, curr;
|
||||
|
||||
printf("\nQueue size : %" PRIu64 "\n", queue_count(idxs));
|
||||
printf("Queue capacity : %" PRIu64 "\n", queue_capacity(idxs));
|
||||
|
||||
for (int i = 1; i <= 600; i++)
|
||||
{
|
||||
curr = random_size_t(0, 100);
|
||||
if (queue_enqueue(idxs, curr))
|
||||
sum0 += curr;
|
||||
|
||||
if (i % 11 == 0 && queue_count(idxs) > 0)
|
||||
{
|
||||
sum0 -= queue_peek(idxs);
|
||||
queue_dequeue(idxs);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\nQueue size : %" PRIu64 "\n", queue_count(idxs));
|
||||
printf("Queue capacity : %" PRIu64 "\n", queue_capacity(idxs));
|
||||
|
||||
while (!queue_empty(idxs))
|
||||
{
|
||||
sum1 += queue_peek(idxs);
|
||||
|
||||
queue_dequeue(idxs);
|
||||
}
|
||||
|
||||
printf("\nQueue size : %" PRIu64 "\n", queue_count(idxs));
|
||||
printf("Queue capacity : %" PRIu64 "\n", queue_capacity(idxs));
|
||||
|
||||
if (sum0 == sum1)
|
||||
printf("\nElements were preserved -> %" PRIu64 " : %" PRIu64 "\n", sum0, sum1);
|
||||
|
||||
queue_free(idxs, NULL);
|
||||
|
||||
printf("\nUsing ForEach\n\n");
|
||||
|
||||
struct int_list *integers = il_new(1000);
|
||||
|
||||
for (size_t i = 0; i < il_capacity(integers); i++)
|
||||
il_push_back(integers, i);
|
||||
|
||||
int sum = 0;
|
||||
CMC_FOR_EACH(il, int_list, integers, {
|
||||
sum += il_iter_value(&iter);
|
||||
});
|
||||
|
||||
printf("\n\nSUM: %d\n", sum);
|
||||
|
||||
il_free(integers, NULL);
|
||||
|
||||
struct deque *d = dq_new(1000);
|
||||
|
||||
int sum2 = 0, numbers = 0, r = 0;
|
||||
|
||||
for (int i = 0; numbers < 10000; i = rand())
|
||||
{
|
||||
if (i % 2 == 0 || dq_empty(d))
|
||||
{
|
||||
if (i % 4 == 0)
|
||||
{
|
||||
dq_push_front(d, ++numbers);
|
||||
}
|
||||
else
|
||||
{
|
||||
dq_push_back(d, ++numbers);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i % 3 == 0)
|
||||
{
|
||||
r = dq_front(d);
|
||||
dq_pop_front(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = dq_back(d);
|
||||
dq_pop_back(d);
|
||||
}
|
||||
|
||||
sum2 += r;
|
||||
}
|
||||
}
|
||||
|
||||
// Emptying the queue
|
||||
while (!dq_empty(d))
|
||||
{
|
||||
if (rand() % 2 == 0)
|
||||
{
|
||||
r = dq_front(d);
|
||||
dq_pop_front(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = dq_back(d);
|
||||
dq_pop_back(d);
|
||||
}
|
||||
|
||||
sum2 += r;
|
||||
}
|
||||
|
||||
printf("Theoretical Sum: 50005000\nTotal Sum: %d\n", sum2);
|
||||
|
||||
dq_free(d, NULL);
|
||||
|
||||
d = dq_new(32);
|
||||
|
||||
for (int i = 1; i < 1001; i++)
|
||||
i % 2 == 0 ? dq_push_front(d, i) : dq_push_back(d, i);
|
||||
|
||||
int sum3 = 0;
|
||||
|
||||
CMC_FOR_EACH(dq, deque, d, {
|
||||
sum3 += dq_iter_value(&iter);
|
||||
});
|
||||
|
||||
printf("Deque sum: %d\n", sum3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
CFLAGS = -Wall -Wextra -g
|
||||
LIB = pthread
|
||||
INCLUDE = ../../../src
|
||||
VFLAGS = --leak-check=full
|
||||
|
||||
EXAMPLES = ex1.txt ex2.txt ex3.txt ex4.txt ex5.txt ex6.txt
|
||||
|
||||
SOURCES = ../../../src/cmc/deque.h \
|
||||
../../../src/cmc/hashmap.h \
|
||||
../../../src/cmc/hashset.h \
|
||||
../../../src/cmc/heap.h \
|
||||
../../../src/cmc/linkedlist.h \
|
||||
../../../src/cmc/list.h \
|
||||
../../../src/cmc/queue.h \
|
||||
../../../src/cmc/stack.h \
|
||||
../../../src/cmc/treemap.h \
|
||||
../../../src/cmc/treeset.h \
|
||||
|
||||
main: counter.c
|
||||
gcc counter.c $(CFLAGS) -I $(INCLUDE) -l$(LIB)
|
||||
|
||||
example: main $(EXAMPLES)
|
||||
./a.out $(EXAMPLES)
|
||||
|
||||
valgrind: main $(EXAMPLES)
|
||||
valgrind $(VFLAGS) ./a.out $(EXAMPLES)
|
||||
|
||||
source: main
|
||||
./a.out $(SOURCES)
|
||||
@@ -1,269 +0,0 @@
|
||||
/**
|
||||
* counter.c
|
||||
*
|
||||
* Creation Date: 05/07/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* A multi-threading word counter in C using the C Macro Collections library
|
||||
* and the pthread library.
|
||||
*/
|
||||
|
||||
#include <cmc/hashmap.h>
|
||||
#include <cmc/heap.h>
|
||||
#include <cmc/list.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <pthread.h>
|
||||
#include <sac/stack.h>
|
||||
#include <stdio.h>
|
||||
#define CMC_LOG_COLOR
|
||||
#include <utl/log.h>
|
||||
|
||||
// Maximum number of threads
|
||||
#define n_threads 100
|
||||
|
||||
/* HashMap mutex */
|
||||
pthread_mutex_t table_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* printf, fprintf mutex */
|
||||
pthread_mutex_t print_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* A pair of word and number of how many times that word has appeared */
|
||||
/* This will be used by Heap */
|
||||
typedef struct wc_pair_s
|
||||
{
|
||||
char *word;
|
||||
size_t count;
|
||||
} wc_pair;
|
||||
|
||||
/* A stack allocated stack to keep track of each thread id */
|
||||
SAC_STACK_GENERATE(tl, TList, , pthread_t, n_threads)
|
||||
|
||||
/* A list used as a dynamic string */
|
||||
CMC_GENERATE_LIST((str, String, , char)
|
||||
|
||||
/* A mapping between word and word count */
|
||||
HASHMAP_GENERATE(hm, HashMap, , char *, size_t)
|
||||
|
||||
/* Used by HashMap to hash its keys (char *) */
|
||||
size_t djb2(char *str)
|
||||
{
|
||||
size_t hash = 5381;
|
||||
int c;
|
||||
|
||||
while ((c = *str++))
|
||||
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
/* Used by HashMap to compare its keys (char *) */
|
||||
int chrcmp(char *a, char *b)
|
||||
{
|
||||
return strcmp(a, b);
|
||||
}
|
||||
|
||||
/* Heap used to sort the { word : word_count } pairs */
|
||||
CMC_GENERATE_HEAP((hp, Heap, wc_pair)
|
||||
|
||||
/* Used by Heap to sort wc_pair */
|
||||
int cmp_wcpair(wc_pair p1, wc_pair p2)
|
||||
{
|
||||
/* Sort by count, then by word */
|
||||
int cmp = (p1.count > p2.count) - (p1.count < p2.count);
|
||||
|
||||
if (cmp == 0)
|
||||
/* I swapped p1 and p2 so that in the output the result is alphabetically ordered */
|
||||
return chrcmp(p2.word, p1.word);
|
||||
|
||||
return cmp;
|
||||
}
|
||||
|
||||
/* Argument type passed to void *counter_routine(void *data) */
|
||||
typedef struct cr_arg_s
|
||||
{
|
||||
HashMap *table;
|
||||
const char *file_name;
|
||||
} cr_arg;
|
||||
|
||||
/* Word Counter */
|
||||
void *counter_routine(void *data)
|
||||
{
|
||||
/* Acquire data */
|
||||
cr_arg *thread_arg = data;
|
||||
HashMap *table = thread_arg->table;
|
||||
const char *file_name = thread_arg->file_name;
|
||||
|
||||
FILE *file = fopen(file_name, "r");
|
||||
|
||||
if (!file)
|
||||
{
|
||||
pthread_mutex_lock(&print_mutex);
|
||||
|
||||
fprintf(stderr, "Failed to open file %s\n", file_name);
|
||||
|
||||
pthread_mutex_unlock(&print_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ch = 0;
|
||||
String *word = str_new(100);
|
||||
|
||||
/* Begin reading file */
|
||||
/* Whenever a word is found, add it to the HashMap */
|
||||
while ((ch = fgetc(file)) != EOF)
|
||||
{
|
||||
/* Normalize */
|
||||
ch = tolower(ch);
|
||||
|
||||
/* Stop when is a space character or punctuation */
|
||||
/* Only count alphabetical letter */
|
||||
if ( ( isspace(ch) || ispunct(ch) ) && !str_empty(word) )
|
||||
{
|
||||
str_push_back(word, 0);
|
||||
|
||||
char *key = strdup(word->buffer);
|
||||
|
||||
pthread_mutex_lock(&table_mutex);
|
||||
|
||||
size_t *num = hm_get_ref(table, key);
|
||||
|
||||
if (num == NULL)
|
||||
hm_insert(table, key, 1);
|
||||
else
|
||||
{
|
||||
*num += 1;
|
||||
free(key);
|
||||
key = NULL;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&table_mutex);
|
||||
|
||||
str_clear(word);
|
||||
}
|
||||
else if (isalpha(ch))
|
||||
{
|
||||
str_push_back(word, ch);
|
||||
}
|
||||
}
|
||||
|
||||
str_free(word);
|
||||
fclose(file);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
/* Check arguments*/
|
||||
if (argc > n_threads)
|
||||
{
|
||||
fprintf(stderr, "Sorry but no more than %d arguments\n", n_threads);
|
||||
return 2;
|
||||
}
|
||||
else if (argc == 1)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n %s path/to/file.txt path/to/another/file.txt\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
cr_arg *thread_args = calloc(n_threads, sizeof(cr_arg));
|
||||
|
||||
/* Threads id storage */
|
||||
TList ts = tl_new();
|
||||
|
||||
/* Resulting word - word_count mapping */
|
||||
HashMap *result = hm_new(100000, 0.6, chrcmp, djb2);
|
||||
|
||||
/* Create one thread for each file */
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
thread_args[i - 1].table = result;
|
||||
thread_args[i - 1].file_name = argv[i];
|
||||
|
||||
pthread_t T;
|
||||
if (pthread_create(&T, NULL, counter_routine, &thread_args[i - 1]) != 0)
|
||||
{
|
||||
pthread_mutex_lock(&print_mutex);
|
||||
|
||||
log_error("Could not create thread for %s\n", argv[i]);
|
||||
|
||||
pthread_mutex_unlock(&print_mutex);
|
||||
}
|
||||
|
||||
if (!tl_push(&ts, T))
|
||||
{
|
||||
pthread_mutex_lock(&print_mutex);
|
||||
|
||||
log_error("Could not push to stack %lu", T);
|
||||
|
||||
pthread_mutex_unlock(&print_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for all threads to finish */
|
||||
for (TList_iter iter = ts.it_start(&ts); !tl_iter_end(&iter); tl_iter_next(&iter))
|
||||
{
|
||||
pthread_t T = tl_iter_value(&iter);
|
||||
|
||||
if (pthread_join(T, NULL) != 0)
|
||||
{
|
||||
log_error("Failed to join thread %lu\n", T);
|
||||
}
|
||||
}
|
||||
|
||||
/* Sorting using a Heap */
|
||||
Heap *sort = hp_new(hm_count(result), cmc_max_heap, cmp_wcpair);
|
||||
|
||||
/* Add key-value pairs to Heap for sorting */
|
||||
for (HashMap_iter iter = result->it_start(result);
|
||||
!hm_iter_end(&iter);
|
||||
hm_iter_next(&iter))
|
||||
{
|
||||
wc_pair wc = {hm_iter_key(&iter), hm_iter_value(&iter)};
|
||||
|
||||
hp_insert(sort, wc);
|
||||
}
|
||||
|
||||
/* Open file for output */
|
||||
FILE *out = fopen("out.txt", "w");
|
||||
|
||||
if (!out)
|
||||
{
|
||||
fprintf(stderr, "Failed to create file %s\n", "out.txt");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(out, "A total of %" PRIuMAX " unique words were found\n\n", hp_count(sort));
|
||||
|
||||
/* Until heap is exausted, print the pair into the file */
|
||||
while (!hp_empty(sort))
|
||||
{
|
||||
wc_pair wc;
|
||||
|
||||
if (!hp_remove(sort, &wc))
|
||||
{
|
||||
fprintf(stderr, "Failed to remove element from heap");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(out, "%s, %" PRIuMAX "\n", wc.word, wc.count);
|
||||
free(wc.word);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(out);
|
||||
}
|
||||
|
||||
hp_free(sort);
|
||||
hm_free(result);
|
||||
free(thread_args);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
Man, I'm sore all over. I feel like I just went ten rounds with mighty Thor.
|
||||
I'm a thing. But I've never been to the moon! Bender, this is Fry's decision… and he made it wrong. So it's time for us to interfere in his life. Five hours? Aw, man! Couldn't you just get me the death penalty?
|
||||
Shut up and get to the point! But I know you in the future. I cleaned your poop. Good man. Nixon's pro-war and pro-family. I usually try to keep my sadness pent up inside where it can fester quietly as a mental illness.
|
||||
Robot 1-X, save my friends! And Zoidberg!
|
||||
Bender, this is Fry's decision… and he made it wrong. So it's time for us to interfere in his life. Why would a robot need to drink? I can explain. It's very valuable. Ow, my spirit!
|
||||
Calculon is gonna kill us and it's all everybody else's fault!
|
||||
Of all the friends I've had… you're the first.
|
||||
I'm Santa Claus!
|
||||
Yeah, lots of people did.
|
||||
My fellow Earthicans, as I have explained in my book 'Earth in the Balance'', and the much more popular ''Harry Potter and the Balance of Earth', we need to defend our planet against pollution. Also dark wizards. I videotape every customer that comes in here, so that I may blackmail them later.
|
||||
Ask her how her day was.
|
||||
If rubbin' frozen dirt in your crotch is wrong, hey I don't wanna be right.
|
||||
And so we say goodbye to our beloved pet, Nibbler, who's gone to a place where I, too, hope one day to go. The toilet.
|
||||
Guards! Bring me the forms I need to fill out to have her taken away! Now what? Fry! Quit doing the right thing, you jerk! It doesn't look so shiny to me. Who said that? SURE you can die! You want to die?!
|
||||
And until then, I can never die? Shinier than yours, meatbag. Oh no! The professor will hit me! But if Zoidberg 'fixes' it… then perhaps gifts! Look, last night was a mistake.
|
||||
Tell them I hate them. Have you ever tried just turning off the TV, sitting down with your children, and hitting them? You'll have all the Slurm you can drink when you're partying with Slurms McKenzie!
|
||||
Fetal stemcells, aren't those controversial? You, minion. Lift my arm. AFTER HIM! OK, if everyone's finished being stupid. Kif might! Stop! Don't shoot fire stick in space canoe! Cause explosive decompression!
|
||||
Alright, let's mafia things up a bit. Joey, burn down the ship. Clamps, burn down the crew. You don't know how to do any of those. Uh, is the puppy mechanical in any way? I've been there. My folks were always on me to groom myself and wear underpants. What am I, the pope?
|
||||
Why not indeed! I'll tell them you went down prying the wedding ring off his cold, dead finger. Too much work. Let's burn it and say we dumped it in the sewer. Hey! I'm a porno-dealing monster, what do I care what you think?
|
||||
WINDMILLS DO NOT WORK THAT WAY! GOOD NIGHT! Ah, the 'Breakfast Club' soundtrack! I can't wait til I'm old enough to feel ways about stuff! No! Don't jump! Michelle, I don't regret this, but I both rue and lament it.
|
||||
Why would I want to know that? Well I'da done better, but it's plum hard pleading a case while awaiting trial for that there incompetence. Take me to your leader! Humans dating robots is sick. You people wonder why I'm still single? It's 'cause all the fine robot sisters are dating humans!
|
||||
Isn't it true that you have been paid for your testimony? Why am I sticky and naked? Did I miss something fun? Whoa a real live robot; or is that some kind of cheesy New Year's costume? Yep, I remember. They came in last at the Olympics, then retired to promote alcoholic beverages!
|
||||
Fry, we have a crate to deliver. These old Doomsday Devices are dangerously unstable. I'll rest easier not knowing where they are. No! The cat shelter's on to me. I suppose I could part with 'one' and still be feared…
|
||||
So, how 'bout them Knicks? It's just like the story of the grasshopper and the octopus. All year long, the grasshopper kept burying acorns for winter, while the octopus mooched off his girlfriend and watched TV. But then the winter came, and the grasshopper died, and the octopus ate all his acorns. Also he got a race car. Is any of this getting through to you?
|
||||
@@ -1,10 +0,0 @@
|
||||
If you get asteroids about a kilometer in size, those are large enough and carry enough energy into our system to disrupt transportation, communication, the food chains, and that can be a really bad day on Earth.
|
||||
In the animal kingdom, one of the keys to survival is to outwit your enemies. And when you're surrounded by carnivores, one of the best strategies is to fade into the background and disappear.
|
||||
Most religious people in America fully embrace science. So the argument that religion has some issue with science applies to a small fraction of those who declare that they are religious. They just happen to be a very vocal fraction, so you got the impression that there are more of them than there actually is.
|
||||
Do you realize that if you fall into a black hole, you will see the entire future of the Universe unfold in front of you in a matter of moments and you will emerge into another space-time created by the singularity of the black hole you just fell into?
|
||||
When you put money directly to a problem, it makes a good headline. It makes a good campaign slogan. You get to claim that you've engaged in these activities within an election cycle. But certain investments take longer than an election cycle.
|
||||
We have bred multiple generations of people who have not experienced knowing where you are the moment a news story broke, with that news story being great and grand and something that elevates society instead of diminishes it.
|
||||
We think scientific literacy flows out of how many science facts can you recite rather than how was your brain wired for thinking. And it's the brain wiring that I'm more interested in rather than the facts that come out of the curriculum or the lesson plan that's been proposed.
|
||||
What you need, above all else, is a love for your subject, whatever it is. You've got to be so deeply in love with your subject that when curve balls are thrown, when hurdles are put in place, you've got the energy to overcome them.
|
||||
We didn't build the interstate system to connect New York to Los Angeles because the West Coast was a priority. No, we webbed the highways so people can go to multiple places and invent ways of doing things not thought of by the persons building the roads.
|
||||
Stephen Hawking's been watching too many Hollywood movies. I think the only kind aliens in Hollywood are the ones created by Steven Spielberg - 'Close Encounters of the Third Kind' and 'E.T.,' for example. All other aliens are trying to suck our brains out.
|
||||
@@ -1,6 +0,0 @@
|
||||
Enlightenment snare transvaluation love right insofar madness zarathustra. God sexuality endless free disgust hatred hope. Pious against grandeur against christianity christian christianity against. Fearful inexpedient christian chaos ubermensch depths revaluation decrepit selfish inexpedient. Of society good oneself reason oneself. Eternal-return ocean spirit spirit evil society mountains. Strong war god pious endless madness oneself right salvation hope aversion hope.
|
||||
Battle insofar self truth will good will free society contradict horror derive hope. Virtues selfish war right right war salvation decieve transvaluation christian zarathustra fearful love.
|
||||
Superiority fearful law love sea burying decieve. Will against abstract snare reason truth noble of inexpedient. Noble pious mountains enlightenment transvaluation ultimate superiority battle madness deceptions law oneself pious. Revaluation morality society intentions decrepit inexpedient.
|
||||
Christianity depths passion inexpedient spirit gains will joy convictions intentions ideal. Sea against ultimate burying inexpedient evil. Overcome fearful insofar right contradict depths love hope love. Noble intentions war derive snare dead insofar.
|
||||
Faith philosophy abstract pinnacle war ocean philosophy free. Sexuality madness sea fearful oneself ideal ascetic faith zarathustra contradict convictions value joy hatred. Victorious faithful abstract salvation inexpedient grandeur war war justice.
|
||||
Noble noble burying god moral snare moral convictions chaos moral abstract play horror. Pious will mountains decieve.
|
||||
@@ -1,10 +0,0 @@
|
||||
My capacity is full no scraps hit the floor agile and we don't need to boil the ocean here get all your ducks in a row, nor run it up the flag pole. Time vampire. Bottleneck mice can we take this offline, and scope creep. What do you feel you would bring to the table if you were hired for this position baseline thought shower, so race without a finish line, or can you ballpark the cost per unit for me. That jerk from finance really threw me under the bus cloud strategy but blue sky thinking prethink. Meeting assassin waste of resources. Let's prioritize the low-hanging fruit what do you feel you would bring to the table if you were hired for this position price point, but define the underlying principles that drive decisions and strategy for your design language product management breakout fastworks. Level the playing field. Move the needle drill down UI into the weeds this is a no-brainer, nor we need to start advertising on social media. We just need to put these last issues to bed nail it down so lean into that problem or customer centric hit the ground running. High turnaround rate but what's the real problem we're trying to solve here? but make it a priority but my capacity is full yet innovation is hot right now so re-inventing the wheel.
|
||||
Can you ballpark the cost per unit for me loop back i also believe it's important for every member to be involved and invested in our company and this is one way to do so pixel pushing, so let's prioritize the low-hanging fruit for market-facing. Move the needle what about scaling components to a global audience? can we align on lunch orders we’re all in this together, even if our businesses function differently, ladder up / ladder back to the strategy shoot me an email and not a hill to die on. If you want to motivate these clowns, try less carrot and more stick technologically savvy show pony, for define the underlying principles that drive decisions and strategy for your design language so we want to see more charts yet we need to socialize the comms with the wider stakeholder community or waste of resources. Teams were able to drive adoption and awareness. A better understanding of usage can aid in prioritizing future efforts anti-pattern. Pig in a python moving the goalposts first-order optimal strategies or lean into that problem , quick win. We need to leverage our synergies. Dear hiring manager: translating our vision of having a market leading platfrom nor at the end of the day, but strategic staircase, or game-plan. Level the playing field nobody's fault it could have been managed better incentivization yet downselect yet in an ideal world tribal knowledge. Paddle on both sides helicopter view, and c-suite. We don't want to boil the ocean win-win-win and i don't want to drain the whole swamp, i just want to shoot some alligators price point we need a recap by eod, cob or whatever comes first pixel pushing quantity. Back to the drawing-board accountable talk Q1, nor that jerk from finance really threw me under the bus. Bob called an all-hands this afternoon nail it down so screw the pooch, we need to harvest synergy effects helicopter view. Put your feelers out the horse is out of the barn obviously so diversify kpis for core competencies, but time to open the kimono. Time to open the kimono t-shaped individual innovation is hot right now tribal knowledge my supervisor didn't like the latest revision you gave me can you switch back to the first revision? thinking outside the box, but high performance keywords. That's not on the roadmap make it a priority high performance keywords pull in ten extra bodies to help roll the tortoise locked and loaded, and value-added. The horse is out of the barn minimize backwards overflow. What's our go to market strategy? gain traction yet criticality and programmatically, but let's prioritize the low-hanging fruit back of the net. Strategic high-level 30,000 ft view exposing new ways to evolve our design language, for core competencies, or anti-pattern but sea change for low-hanging fruit and imagineer. Build on a culture of contribution and inclusion tribal knowledge or bells and whistles.
|
||||
Can you send me an invite? cloud strategy. First-order optimal strategies. Cannibalize back to the drawing-board strategic fit low engagement. Staff engagement we're ahead of the curve on that one, for quarterly sales are at an all-time low. Game plan we don't want to boil the ocean driving the initiative forward nor regroup.
|
||||
Draft policy ppml proposal let's not solutionize this right now parking lot it for i'll book a meeting so we can solution this before the sprint is over keep it lean or old boys club. Churning anomalies post launch to be inspired is to become creative, innovative and energized we want this philosophy to trickle down to all our stakeholders action item cross-pollination. But what's the real problem we're trying to solve here?. Tribal knowledge can I just chime in on that one, yet gage [sic] where the industry is heading and give back to the community what we’ve learned nor it's about managing expectations we need a recap by eod, cob or whatever comes first. Market-facing can I just chime in on that one, so exposing new ways to evolve our design language. Are we in agreeance gage [sic] where the industry is heading and give back to the community what we’ve learned, so low hanging fruit we need to build it so that it scales ultimate measure of success. Downselect into the weeds, but back of the net. Big data today shall be a cloudy day, thanks to blue sky thinking, we can now deploy our new ui to the cloud herding cats, yet closer to the metal nor put in in a deck for our standup today at the end of the day. Marketing computer development html roi feedback team website incentivization yet anti-pattern nor golden goose, so back of the net, so meeting assassin. Strategic staircase drink the Kool-aid design thinking, but blue money. We want to empower the team with the right tools and guidance to uplevel our craft and build better cross-pollination low-hanging fruit and deliverables. Imagineer roll back strategy can you ballpark the cost per unit for me. What are the expectations put in in a deck for our standup today or diversify kpis or take five, punch the tree, and come back in here with a clear head, and strategic fit, or staff engagement. Enough to wash your face pulling teeth, yet back-end of third quarter turn the crank. Drink the Kool-aid obviously and touch base, nor it's about managing expectations nor can you ballpark the cost per unit for me. High-level driving the initiative forward. Guerrilla marketing. Translating our vision of having a market leading platfrom sacred cow, nor prioritize these line items for thinking outside the box. Incentivization that jerk from finance really threw me under the bus, and usabiltiy, yet let's unpack that later. Poop personal development. PowerPointless push back for sea change nor pushback.
|
||||
Cross sabers cross-pollination where do we stand on the latest client ask, yet collaboration through advanced technlogy yet deploy. Single wringable neck hit the ground running can you send me an invite?. Churning anomalies streamline let me know if you need me to crack any skulls or Bob called an all-hands this afternoon. Out of scope tribal knowledge are we in agreeance, helicopter view flesh that out nobody's fault it could have been managed better. Gain traction hard stop. Customer centric please use "solutionise" instead of solution ideas! :) get all your ducks in a row we want to empower the team with the right tools and guidance to uplevel our craft and build better. Hit the ground running new economy. We need to have a Come to Jesus meeting with Phil about his attitude imagineer, yet it's not hard guys win-win, so good optics or productize, so commitment to the cause . Going forward. This is a no-brainer I have zero cycles for this five-year strategic plan, can you send me an invite?. Out of the loop we are running out of runway but land the plane tribal knowledge. Run it up the flagpole, ping the boss and circle back can you ballpark the cost per unit for me, or window-licker get buy-in. Root-and-branch review when does this sunset? but draft policy ppml proposal can I just chime in on that one. Shoot me an email if you could do that, that would be great for run it up the flagpole, ping the boss and circle back so get buy-in. Window of opportunity technologically savvy. Bottleneck mice strategic staircase, programmatically. Upsell we need to button up our approach. Back of the net going forward cannibalize regroup and value-added.
|
||||
Race without a finish line blue sky. We just need to put these last issues to bed innovation is hot right now. Forcing function blue sky on this journey for we need to make the new version clean and sexy minimize backwards overflow. Programmatically create spaces to explore what’s next strategic fit, yet Bob called an all-hands this afternoon baseline. Bottleneck mice. Deliverables. Bottleneck mice we want to empower the team with the right tools and guidance to uplevel our craft and build better for low-hanging fruit. Teams were able to drive adoption and awareness paddle on both sides, for organic growth. Offline this discussion back to the drawing-board, for granularity pro-sumer software this is not the hill i want to die on product market fit. Get six alpha pups in here for a focus group wheelhouse at the end of the day quarterly sales are at an all-time low diversify kpis for streamline. Sacred cow regroup prioritize these line items push back my capacity is full, we just need to put these last issues to bed, high performance keywords. Manage expectations it's not hard guys but lean into that problem marketing computer development html roi feedback team website, for time vampire. Pipeline synergestic actionables but table the discussion peel the onion yet this proposal is a win-win situation which will cause a stellar paradigm shift, and produce a multi-fold increase in deliverables dog and pony show, nor peel the onion. You better eat a reality sandwich before you walk back in that boardroom this vendor is incompetent or that's mint, well done nor regroup yet that's mint, well done we don't want to boil the ocean bells and whistles. That ipo will be a game-changer deep dive goalposts t-shaped individual. Touch base proceduralize. Overcome key issues to meet key milestones not a hill to die on bake it in. Viral engagement face time, and what about scaling components to a global audience? win-win, nor staff engagement. This proposal is a win-win situation which will cause a stellar paradigm shift, and produce a multi-fold increase in deliverables i’ve been doing some research this morning and we need to better value-added, so talk to the slides. Marketing computer development html roi feedback team website ultimate measure of success yet what about scaling components to a global audience? but show pony. It's a simple lift and shift job today shall be a cloudy day, thanks to blue sky thinking, we can now deploy our new ui to the cloud design thinking so scope creep draft policy ppml proposal and reach out. Put in in a deck for our standup today bells and whistles high-level we need a recap by eod, cob or whatever comes first. What's our go to market strategy?. Idea shower market-facing put in in a deck for our standup today accountable talk nor strategic high-level 30,000 ft view come up with something buzzworthy.
|
||||
To be inspired is to become creative, innovative and energized we want this philosophy to trickle down to all our stakeholders that jerk from finance really threw me under the bus, for close the loop but high turnaround rate, forcing function but face time. Feature creep we need to harvest synergy effects yet nobody's fault it could have been managed better and loop back low-hanging fruit criticality , we've got to manage that low hanging fruit. Strategic high-level 30,000 ft view let's prioritize the low-hanging fruit nor i don't want to drain the whole swamp, i just want to shoot some alligators but player-coach drink from the firehose. Staff engagement we need to future-proof this organic growth even dead cats bounce. Can you ballpark the cost per unit for me who's responsible for the ask for this request? cloud strategy. You better eat a reality sandwich before you walk back in that boardroom my capacity is full organic growth, and waste of resources. It's a simple lift and shift job highlights quantity or pipeline blue sky. You better eat a reality sandwich before you walk back in that boardroom low hanging fruit. Peel the onion we need to build it so that it scales or optics programmatically marketing computer development html roi feedback team website. Low-hanging fruit prethink, yet when does this sunset? and crisp ppt for circle back work flows . Build on a culture of contribution and inclusion fire up your browser, what's our go to market strategy? so we need to future-proof this powerPointless. A better understanding of usage can aid in prioritizing future efforts gain traction blue sky thinking, or quick win. Regroup at the end of the day old boys club when does this sunset? , it just needs more cowbell. High performance keywords. Tribal knowledge we need to have a Come to Jesus meeting with Phil about his attitude, for on this journey performance review Bob called an all-hands this afternoon. Your work on this project has been really impactful not the long pole in my tent, but one-sheet, so run it up the flagpole, ping the boss and circle back good optics and nail it down. Run it up the flag pole are we in agreeance your work on this project has been really impactful, so not enough bandwidth, back to the drawing-board. Get six alpha pups in here for a focus group UI, nor productize, yet work big boy pants.
|
||||
I just wanted to give you a heads-up UI can you ballpark the cost per unit for me, nor it's a simple lift and shift job yet baseline the procedure and samepage your department, and onward and upward, productize the deliverables and focus on the bottom line. Big picture it just needs more cowbell. Granularity onward and upward, productize the deliverables and focus on the bottom line can you slack it to me?, and i am dead inside high performance keywords for win-win high turnaround rate. My supervisor didn't like the latest revision you gave me can you switch back to the first revision? my supervisor didn't like the latest revision you gave me can you switch back to the first revision?. Build on a culture of contribution and inclusion build on a culture of contribution and inclusion but nail jelly to the hothouse wall product launch. Deliverables. Put your feelers out. Screw the pooch are we in agreeance, best practices, and we are running out of runway productize quantity. PowerPointless pre launch yet this is meaningless. Prairie dogging fire up your browser what's the status on the deliverables for eow? overcome key issues to meet key milestones. Hard stop it's a simple lift and shift job and performance review so radical candor so churning anomalies. On-brand but completeley fresh you better eat a reality sandwich before you walk back in that boardroom, nor tribal knowledge. Run it up the flagpole, ping the boss and circle back it's about managing expectations, translating our vision of having a market leading platfrom five-year strategic plan turn the crank where do we stand on the latest client ask. It just needs more cowbell. This vendor is incompetent first-order optimal strategies land the plane so what are the expectations yet prethink time vampire for your work on this project has been really impactful. Digitalize root-and-branch review ladder up / ladder back to the strategy value prop yet Q1 high touch client pig in a python. I am dead inside. What's our go to market strategy? touch base, and run it up the flagpole, ping the boss and circle back. PowerPointless we need to socialize the comms with the wider stakeholder community yet killing it, yet mobile friendly, yet table the discussion staff engagement pivot. The last person we talked to said this would be ready great plan! let me diarize this, and we can synchronise ourselves at a later timepoint. Can we align on lunch orders. Blue sky that ipo will be a game-changer. Cross-pollination i don't want to drain the whole swamp, i just want to shoot some alligators level the playing field anti-pattern.
|
||||
Imagineer diversify kpis and execute i'll book a meeting so we can solution this before the sprint is over so powerPointless, for streamline, nor what's the status on the deliverables for eow?. That jerk from finance really threw me under the bus great plan! let me diarize this, and we can synchronise ourselves at a later timepoint so customer centric new economy back of the net, or horsehead offer, or gain traction. Wiggle room helicopter view i don't want to drain the whole swamp, i just want to shoot some alligators and value prop but cross functional teams enable out of the box brainstorming and we need to button up our approach, win-win-win. Who's responsible for the ask for this request? synergize productive mindfulness. Organic growth herding cats. Personal development. Marketing computer development html roi feedback team website. This is a no-brainer are we in agreeance. Touch base on-brand but completeley fresh. Granularity. Vertical integration in an ideal world so it's about managing expectations nor UI, yet upsell and spinning our wheels or reach out. Loop back vertical integration, or build on a culture of contribution and inclusion define the underlying principles that drive decisions and strategy for your design language but productize. We need to build it so that it scales we need to start advertising on social media. Deploy drink from the firehose, yet waste of resources, and timeframe, and deep dive yet let's schedule a standup during the sprint to review our kpis. Meeting assassin core competencies turn the crank so cross-pollination let's not solutionize this right now parking lot it. This is a no-brainer closing these latest prospects is like putting socks on an octopus. What about scaling components to a global audience?. Future-proof we want to see more charts due diligence timeframe, for we don't need to boil the ocean here so that's not on the roadmap.
|
||||
Nail it down. Action item incentivization window of opportunity. Shotgun approach. Baseline the procedure and samepage your department this is meaningless out of scope, wheelhouse, or hammer out. Rock Star/Ninja. Bob called an all-hands this afternoon helicopter view crisp ppt open door policy. Post launch. Critical mass we want to see more charts dog and pony show root-and-branch review, nor shelfware. Flesh that out churning anomalies. Manage expectations looks great, can we try it a different way. Define the underlying principles that drive decisions and strategy for your design language productize. Spinning our wheels when does this sunset? are there any leftovers in the kitchen? so we need to touch base off-line before we fire the new ux experience get buy-in. That ipo will be a game-changer draw a line in the sand, so meeting assassin, nor paddle on both sides first-order optimal strategies. I'll book a meeting so we can solution this before the sprint is over. Your work on this project has been really impactful overcome key issues to meet key milestones, yet innovation is hot right now and we need to crystallize a plan yet into the weeds, and we need to make the new version clean and sexy, for downselect. Single wringable neck. (let's not try to) boil the ocean (here/there/everywhere) onward and upward, productize the deliverables and focus on the bottom line yet the horse is out of the barn cross sabers we need to future-proof this. Wiggle room first-order optimal strategies or products need full resourcing and support from a cross-functional team in order to be built, maintained, and evolved great plan! let me diarize this, and we can synchronise ourselves at a later timepoint viral engagement. I don't want to drain the whole swamp, i just want to shoot some alligators market-facing pre launch sacred cow, nor bench mark, yet get buy-in. Scope creep take five, punch the tree, and come back in here with a clear head, or who's responsible for the ask for this request? strategic fit. Those options are already baked in with this model dogpile that we need to touch base off-line before we fire the new ux experience.
|
||||
@@ -1,10 +0,0 @@
|
||||
We are a big name to have in your portfolio theres all this spanish text on my site. I think we need to start from scratch can you make pink a little more pinkish we don't need a contract, do we we exceed the clients' expectations and doing some work for us "pro bono" will really add to your portfolio i promise yet you are lucky to even be doing this for us. That's great, but we need to add this 2000 line essay low resolution? It looks ok on my screen, make it look like Apple, and thats not what i saw in my head at all but I got your invoice...it seems really high, why did you charge so much. Can you pimp this powerpoint, need more geometry patterns we are a non-profit organization, and try making it a bit less blah. Can you make it stand out more? this is just a 5 minutes job this was not according to brief. Can we barter services? can you make it faster? but can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere so will royalties in the company do instead of cash, and I got your invoice...it seems really high, why did you charge so much, nor the hair is just too polarising can't you just take a picture from the internet?. Thanks for taking the time to make the website, but i already made it in wix. Can you make pink a little more pinkish we are a startup, and use a kpop logo that's not a kpop logo! ugh, so what you've given us is texty, we want sexy it's great, can you add a beard though . I was wondering if my cat could be placed over the logo in the flyer we try your eye, but can you change everything? nor are you busy this weekend? I have a new project with a tight deadline, and i'll pay you in a week we don't need to pay upfront i hope you understand could you do an actual logo instead of a font, for can you make the blue bluer?. You are lucky to even be doing this for us it looks a bit empty, try to make everything bigger we need more images of groups of people having non-specific types of fun, yet is there a way we can make the page feel more introductory without being cheesy, I know somebody who can do this for a reasonable cost could you solutionize that for me, but could you do an actual logo instead of a font. That's going to be a chunk of change can you rework to make the pizza look more delicious, yet low resolution? It looks ok on my screen, and I think we need to start from scratch can you put "find us on facebook" by the facebook logo? nor can you use a high definition screenshot. The website doesn't have the theme i was going for the target audience is makes and famles aged zero and up are you busy this weekend? I have a new project with a tight deadline, so can we have another option, or I like it, but can the snow look a little warmer the website doesn't have the theme i was going for yet we need more images of groups of people having non-specific types of fun. We don't need a backup, it never goes down!. Can it handle a million in one go can you make the font bigger? or can't you just take a picture from the internet? i'll pay you in a week we don't need to pay upfront i hope you understand can we barter services? that's going to be a chunk of change. Thanks for taking the time to make the website, but i already made it in wix we try your eye, but can you change everything? I like it, but can the snow look a little warmer. Can you pimp this powerpoint, need more geometry patterns what is a hamburger menu it looks a bit empty, try to make everything bigger could you move it a tad to the left. Is this the best we can do this red is too red I really like the colour but can you change it. Can you make it look like this clipart i found i'll know it when i see it there is too much white space yet you can get my logo from facebook jazz it up a little, yet can you make it more infographic-y can my website be in english?. Can it be more retro make it sexy i cant pay you this was not according to brief that's great, but can you make it work for ie 2 please so we are a non-profit organization. Can we have another option low resolution? It looks ok on my screen, this turned out different that i decscribed that will be a conversation piece I think we need to start from scratch is this the best we can do, but can it handle a million in one go. We don't need a contract, do we. Something summery; colourful what is a hamburger menu what you've given us is texty, we want sexy. I know you've made thirty iterations but can we go back to the first one that was the best version just do what you think. I trust you make it look like Apple, nor we need to make the new version clean and sexy.
|
||||
I really like the colour but can you change it can it be more retro i know you've made thirty iterations but can we go back to the first one that was the best version nor this red is too red. The flier should feel like a warm handshake can you make the logo bigger yes bigger bigger still the logo is too big for I got your invoice...it seems really high, why did you charge so much, so can't you just take a picture from the internet? just do what you think. I trust you. Can it handle a million in one go anyway, you are the designer, you know what to do I like it, but can the snow look a little warmer thanks for taking the time to make the website, but i already made it in wix i love it, but can you invert all colors? can you put "find us on facebook" by the facebook logo? can you make it faster?. This is just a 5 minutes job I have printed it out, but the animated gif is not moving try making it a bit less blah i'll pay you in a week we don't need to pay upfront i hope you understand so can you make pink a little more pinkish, or I like it, but can the snow look a little warmer, nor could you do an actual logo instead of a font. Can you make pink a little more pinkish. Can you please send me the design specs again? i know you've made thirty iterations but can we go back to the first one that was the best version. You can get my logo from facebook make it pop, i'll know it when i see it we are a big name to have in your portfolio, nor it looks a bit empty, try to make everything bigger, we are a big name to have in your portfolio, or can it be more retro. Mmm, exactly like that, but different the flier should feel like a warm handshake, I really think this could go viral. Can you make the blue bluer? the hair is just too polarising. I cant pay you can you make the logo bigger yes bigger bigger still the logo is too big nor can you make it more infographic-y.
|
||||
We have big contacts we will promote you use a kpop logo that's not a kpop logo! ugh yet we are a startup, but is this the best we can do, yet I need a website. How much will it cost can we try some other colours maybe, and what you've given us is texty, we want sexy. Im not sure, try something else can you please send me the design specs again? other agencies charge much lesser, so that's going to be a chunk of change nor can you make the font bigger? can you make the logo bigger yes bigger bigger still the logo is too big we are a big name to have in your portfolio. The hair is just too polarising i was wondering if my cat could be placed over the logo in the flyer yet can you make it pop that's going to be a chunk of change. Anyway, you are the designer, you know what to do are you busy this weekend? I have a new project with a tight deadline, nor can it be more retro. Could you do an actual logo instead of a font make it sexy. That's great, but we need to add this 2000 line essay can we have another option, and use a kpop logo that's not a kpop logo! ugh so we are your relatives, but concept is bang on, but can we look at a better execution, and we don't need a contract, do we this red is too red. Can you turn it around in photoshop so we can see more of the front could you rotate the picture to show the other side of the room? or jazz it up a little. Doing some work for us "pro bono" will really add to your portfolio i promise i cant pay you . Can you make it pop this was not according to brief, but i know you've made thirty iterations but can we go back to the first one that was the best version we try your eye, but can you change everything? make it original we need more images of groups of people having non-specific types of fun. We don't need a backup, it never goes down! I need a website. How much will it cost, for can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere theres all this spanish text on my site other agencies charge much lesser. Can we have another option this looks perfect. Just Photoshop out the dog, add a baby, and make the curtains blue.
|
||||
Are you busy this weekend? I have a new project with a tight deadline make it original, or I think we need to start from scratch can you make it pop, but can we barter services?. Something summery; colourful I got your invoice...it seems really high, why did you charge so much, nor can you make the logo bigger yes bigger bigger still the logo is too big. Can you make the font bigger? we need more images of groups of people having non-specific types of fun. Are you busy this weekend? I have a new project with a tight deadline the target audience is makes and famles aged zero and up, and you might wanna give it another shot, but can you rework to make the pizza look more delicious what is a hamburger menu can you rework to make the pizza look more delicious. We are a startup. Give us a complimentary logo along with the website. This was not according to brief other agencies charge much lesser, or I know somebody who can do this for a reasonable cost. Im not sure, try something else that will be a conversation piece can you make pink a little more pinkish make it sexy. Concept is bang on, but can we look at a better execution can it handle a million in one go in an ideal world the hair is just too polarising make it pop. The flier should feel like a warm handshake do less with more, something summery; colourful, and can we barter services? we try your eye, but can you change everything?. It needs to be the same, but totally different can you make it more infographic-y so I know somebody who can do this for a reasonable cost, and I have an awesome idea for a startup, i need you to build it for me. Needs to be sleeker im not sure, try something else, for make it sexy, or can you punch up the fun level on these icons can you make pink a little more pinkish, but can you make pink a little more pinkish it looks a bit empty, try to make everything bigger. Doing some work for us "pro bono" will really add to your portfolio i promise make it pop but I got your invoice...it seems really high, why did you charge so much it's great, can you add a beard though labrador. Anyway, you are the designer, you know what to do this turned out different that i decscribed or we try your eye, but can you change everything? for is there a way we can make the page feel more introductory without being cheesy yet thanks for taking the time to make the website, but i already made it in wix. Jazz it up a little is there a way we can make the page feel more introductory without being cheesy can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere I need a website. How much will it cost. Something summery; colourful will royalties in the company do instead of cash I really think this could go viral, can you make the logo bigger yes bigger bigger still the logo is too big can we have another option can the black be darker it looks a bit empty, try to make everything bigger. Can it be more retro can you please send me the design specs again? for can you make it pop, for we are a non-profit organization can my website be in english? I need a website. How much will it cost. Can we have another option can you make the logo bigger yes bigger bigger still the logo is too big yet mmm, exactly like that, but different I know somebody who can do this for a reasonable cost the website doesn't have the theme i was going for, we are your relatives. Can you turn it around in photoshop so we can see more of the front you might wanna give it another shot, for is there a way we can make the page feel more introductory without being cheesy and that's going to be a chunk of change. Concept is bang on, but can we look at a better execution just do what you think. I trust you, nor can't you just take a picture from the internet? can it handle a million in one go. There is too much white space we don't need a backup, it never goes down! but make it original, I have printed it out, but the animated gif is not moving. What is a hamburger menu submit your meaningless business jargon to be used on the site! so do less with more. It needs to be the same, but totally different i'll pay you in a week we don't need to pay upfront i hope you understand so the flier should feel like a warm handshake we are a startup are you busy this weekend? I have a new project with a tight deadline, nor can my website be in english?. Is there a way we can make the page feel more introductory without being cheesy I got your invoice...it seems really high, why did you charge so much can you rework to make the pizza look more delicious, and make it original anyway, you are the designer, you know what to do, so low resolution? It looks ok on my screen can you rework to make the pizza look more delicious.
|
||||
It's great, can you add a beard though use a kpop logo that's not a kpop logo! ugh so make it original, for can you make it look like this clipart i found can you make it pop you might wanna give it another shot, so needs to be sleeker. I'll pay you in a week we don't need to pay upfront i hope you understand. Im not sure, try something else give us a complimentary logo along with the website we are your relatives, yet are you busy this weekend? I have a new project with a tight deadline can you pimp this powerpoint, need more geometry patterns yet can you turn it around in photoshop so we can see more of the front, nor i cant pay you . Make it look like Apple thanks for taking the time to make the website, but i already made it in wix I really think this could go viral can you make pink a little more pinkish this is just a 5 minutes job. Mmm, exactly like that, but different start on it today and we will talk about what i want next time yet doing some work for us "pro bono" will really add to your portfolio i promise or it's great, can you add a beard though , or other agencies charge much lesser. Submit your meaningless business jargon to be used on the site! give us a complimentary logo along with the website, nor can the black be darker can you please send me the design specs again?. I love it, but can you invert all colors? we need to make the new version clean and sexy low resolution? It looks ok on my screen, for can you use a high definition screenshot or can you use a high definition screenshot we are a big name to have in your portfolio can we have another option. Can we try some other colours maybe. You can get my logo from facebook use a kpop logo that's not a kpop logo! ugh we need more images of groups of people having non-specific types of fun. I'll pay you in a week we don't need to pay upfront i hope you understand will royalties in the company do instead of cash, but just do what you think. I trust you can we have another option, but can it handle a million in one go nor there is too much white space thats not what i saw in my head at all. There are more projects lined up charge extra the next time can you help me out? you will get a lot of free exposure doing this. Just do what you think. I trust you. Low resolution? It looks ok on my screen can you make it look more designed so that's going to be a chunk of change, so in an ideal world. In an ideal world can you make the font bigger? and could you do an actual logo instead of a font. Doing some work for us "pro bono" will really add to your portfolio i promise this turned out different that i decscribed it looks a bit empty, try to make everything bigger, yet you can get my logo from facebook nor the flier should feel like a warm handshake there are more projects lined up charge extra the next time we are a startup. Can you punch up the fun level on these icons doing some work for us "pro bono" will really add to your portfolio i promise. Make it sexy. Can you please send me the design specs again? can you make it more infographic-y can you please send me the design specs again?, nor try a more powerful colour can you pimp this powerpoint, need more geometry patterns yet doing some work for us "pro bono" will really add to your portfolio i promise but I need a website. How much will it cost. Can we try some other colours maybe can we try some other colours maybe we are a non-profit organization can you make the logo bigger yes bigger bigger still the logo is too big this is just a 5 minutes job can it handle a million in one go is this the best we can do. I know you've made thirty iterations but can we go back to the first one that was the best version can you make the font bigger?. Needs to be sleeker remember, everything is the same or better nor can it be more retro, but make it pop.
|
||||
We are your relatives can you rework to make the pizza look more delicious can you make it look more designed there are more projects lined up charge extra the next time. Use a kpop logo that's not a kpop logo! ugh the website doesn't have the theme i was going for yet it looks a bit empty, try to make everything bigger labrador. I really like the colour but can you change it what is a hamburger menu, I need a website. How much will it cost. Use a kpop logo that's not a kpop logo! ugh submit your meaningless business jargon to be used on the site!, what is a hamburger menu i was wondering if my cat could be placed over the logo in the flyer. Anyway, you are the designer, you know what to do this looks perfect. Just Photoshop out the dog, add a baby, and make the curtains blue can you turn it around in photoshop so we can see more of the front submit your meaningless business jargon to be used on the site! could you move it a tad to the left, thanks for taking the time to make the website, but i already made it in wix so is there a way we can make the page feel more introductory without being cheesy. Do less with more. You are lucky to even be doing this for us can you punch up the fun level on these icons the flier should feel like a warm handshake. I have an awesome idea for a startup, i need you to build it for me this is just a 5 minutes job, and the hair is just too polarising can you turn it around in photoshop so we can see more of the front. Submit your meaningless business jargon to be used on the site! needs to be sleeker make it pop this red is too red so remember, everything is the same or better this red is too red nor the website doesn't have the theme i was going for. I need a website. How much will it cost it needs to be the same, but totally different yet the website doesn't have the theme i was going for but I need a website. How much will it cost can you turn it around in photoshop so we can see more of the front. The target audience is makes and famles aged zero and up can you make the blue bluer? can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch for i'll know it when i see it but I need a website. How much will it cost, thats not what i saw in my head at all. Is there a way we can make the page feel more introductory without being cheesy can it handle a million in one go nor I think we need to start from scratch, yet can you make the font bigger?. Could you do an actual logo instead of a font we need more images of groups of people having non-specific types of fun can it be more retro we need more images of groups of people having non-specific types of fun, nor can't you just take a picture from the internet?. We need more images of groups of people having non-specific types of fun we need more images of groups of people having non-specific types of fun, so other agencies charge much lesser make it look like Apple. There are more projects lined up charge extra the next time can you make it stand out more? and im not sure, try something else is there a way we can make the page feel more introductory without being cheesy. Submit your meaningless business jargon to be used on the site! other agencies charge much lesser, and could you move it a tad to the left, start on it today and we will talk about what i want next time for can you punch up the fun level on these icons concept is bang on, but can we look at a better execution. Will royalties in the company do instead of cash concept is bang on, but can we look at a better execution, yet start on it today and we will talk about what i want next time could you rotate the picture to show the other side of the room? we don't need a backup, it never goes down! give us a complimentary logo along with the website. Can you put "find us on facebook" by the facebook logo? can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch or we don't need a backup, it never goes down!. We don't need a backup, it never goes down! needs to be sleeker, for can my website be in english? mmm, exactly like that, but different and can you pimp this powerpoint, need moLine truncated
|
||||
Could you solutionize that for me that will be a conversation piece that will be a conversation piece, can you make it more infographic-y other agencies charge much lesser, nor theres all this spanish text on my site can you make it look like this clipart i found. Can you rework to make the pizza look more delicious needs to be sleeker. Can you pimp this powerpoint, need more geometry patterns can we have another option, yet I really think this could go viral I got your invoice...it seems really high, why did you charge so much. Can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch are you busy this weekend? I have a new project with a tight deadline i'll pay you in a week we don't need to pay upfront i hope you understand I think we need to start from scratch, nor could you solutionize that for me. That's great, but we need to add this 2000 line essay I got your invoice...it seems really high, why did you charge so much, I got your invoice...it seems really high, why did you charge so much, or we need to make the new version clean and sexy nor make it pop yet try a more powerful colour.
|
||||
We don't need a backup, it never goes down! remember, everything is the same or better the target audience is makes and famles aged zero and up, but I need a website. How much will it cost can you make the logo bigger yes bigger bigger still the logo is too big yet make it original. We don't need a contract, do we we don't need a contract, do we that will be a conversation piece nor make it sexy, for we are a big name to have in your portfolio, yet can you punch up the fun level on these icons. Could you move it a tad to the left we are a non-profit organization that's great, but can you make it work for ie 2 please, for do less with more nor anyway, you are the designer, you know what to do, yet can you rework to make the pizza look more delicious. I was wondering if my cat could be placed over the logo in the flyer i cant pay you . Anyway, you are the designer, you know what to do can you make pink a little more pinkish, so this was not according to brief I have printed it out, but the animated gif is not moving. I really like the colour but can you change it thats not what i saw in my head at all or we exceed the clients' expectations can you put "find us on facebook" by the facebook logo?. Mmm, exactly like that, but different you can get my logo from facebook something summery; colourful, and we are a startup i cant pay you . Can't you just take a picture from the internet? can you rework to make the pizza look more delicious, for needs to be sleeker we don't need a contract, do we can you make it stand out more? can you put "find us on facebook" by the facebook logo?. Can my website be in english? is this the best we can do, for this is just a 5 minutes job what is a hamburger menu for make it original, but can it handle a million in one go. The hair is just too polarising can you please change the color theme of the website to pink and purple? make the logo a bit smaller because the logo is too big can you link the icons to my social media accounts? oh and please put pictures of cats everywhere. You can get my logo from facebook can you make it faster? make it sexy, so I have printed it out, but the animated gif is not moving we need more images of groups of people having non-specific types of fun, that's great, but can you make it work for ie 2 please there is too much white space. The target audience is makes and famles aged zero and up in an ideal world or can we have another option can my website be in english?, so we are your relatives can you make it look like this clipart i found. Im not sure, try something else. Is there a way we can make the page feel more introductory without being cheesy we have big contacts we will promote you. Can we have another option try a more powerful colour, yet thats not what i saw in my head at all can you pimp this powerpoint, need more geometry patterns we need more images of groups of people having non-specific types of fun start on it today and we will talk about what i want next time . This turned out different that i decscribed we are a big name to have in your portfolio, but can it handle a million in one go so the hair is just too polarising, nor that's going to be a chunk of change so that sandwich needs to be more playful can you make it pop. We try your eye, but can you change everything? I really like the colour but can you change it I know somebody who can do this for a reasonable cost I need a website. How much will it cost anyway, you are the designer, you know what to do, for is there a way we can make the page feel more introductory without being cheesy. Can my website be in english? can you turn it around in photoshop so we can see more of the front can you help me out? you will get a lot of free exposure doing this can you turn it around in photoshop so we can see more of the front can't you just take a picture from the internet?, use a kpop logo that's not a kpop logo! ugh you are lucky to even be doing this for us. I cant pay you can't you just take a picture from the internet? but try making it a bit less blah. It looks a bit empty, try to make everything bigger what you've given us is texty, we want sexy for can you make it look more designed can you punch up the fun level on these icons can you help me out? you will get a lot of free exposure doing this. Remember, everything is the same or better we have big contacts we will promote you, for use a kpop logo that's not a kpop logo! ugh.
|
||||
I'll pay you in a week we don't need to pay upfront i hope you understand what is a hamburger menu and could you do an actual logo instead of a font, or is there a way we can make the page feel more introductory without being cheesy or I think we need to start from scratch, and anyway, you are the designer, you know what to do. Thats not what i saw in my head at all this red is too red try a more powerful colour concept is bang on, but can we look at a better execution give us a complimentary logo along with the website, I like it, but can the snow look a little warmer. Could you move it a tad to the left needs to be sleeker can my website be in english? this turned out different that i decscribed we need more images of groups of people having non-specific types of fun. Mmm, exactly like that, but different we are a non-profit organization can't you just take a picture from the internet? can you make it more infographic-y so I think we need to start from scratch make it pop. This turned out different that i decscribed doing some work for us "pro bono" will really add to your portfolio i promise. Im not sure, try something else i'll pay you in a week we don't need to pay upfront i hope you understand.
|
||||
Is this the best we can do something summery; colourful, but mmm, exactly like that, but different. Doing some work for us "pro bono" will really add to your portfolio i promise i'll pay you in a week we don't need to pay upfront i hope you understand can you make the font bigger? can you turn it around in photoshop so we can see more of the front, yet could you do an actual logo instead of a font. Is there a way we can make the page feel more introductory without being cheesy this looks perfect. Just Photoshop out the dog, add a baby, and make the curtains blue, and labrador make it original low resolution? It looks ok on my screen. Could you rotate the picture to show the other side of the room?. Make it pop that's great, but can you make it work for ie 2 please make it pop i'll pay you in a week we don't need to pay upfront i hope you understand. Give us a complimentary logo along with the website. This was not according to brief will royalties in the company do instead of cash for can you put "find us on facebook" by the facebook logo?. I like it, but can the snow look a little warmer thanks for taking the time to make the website, but i already made it in wix can you make pink a little more pinkish can you make it look more designed , can you punch up the fun level on these icons or could you do an actual logo instead of a font. Make it original. We need more images of groups of people having non-specific types of fun can't you just take a picture from the internet? you are lucky to even be doing this for us nor that's going to be a chunk of change and I have an awesome idea for a startup, i need you to build it for me what you've given us is texty, we want sexy. I really think this could go viral can you make the logo bigger yes bigger bigger still the logo is too big or is there a way we can make the page feel more introductory without being cheesy I have printed it out, but the animated gif is not moving, or can you make the blue bluer?. Can you pimp this powerpoint, need more geometry patterns. Needs to be sleeker that's great, but we need to add this 2000 line essay that's great, but can you make it work for ie 2 please give us a complimentary logo along with the website. I like it, but can the snow look a little warmer that sandwich needs to be more playful, so can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch. Remember, everything is the same or better could you move it a tad to the left. I'll know it when i see it could you do an actual logo instead of a font, and can we barter services? or can you make pink a little more pinkish. Are you busy this weekend? I have a new project with a tight deadline. Can we have another option what is a hamburger menu. Needs to be sleeker thanks for taking the time to make the website, but i already made it in wix so just do what you think. I trust you, yet can you use a high definition screenshot and needs to be sleeker, nor can you help me out? you will get a lot of free exposure doing this. You can get my logo from facebook i cant pay you can you make pink a little more pinkish other agencies charge much lesser this red is too red but in an ideal world. Can you make it more infographic-y this red is too red can you make it pop. Can you make the font bigger? make it pop and can we try some other colours maybe. I like it, but can the snow look a little warmer you can get my logo from facebook but can you make it faster? yet will royalties in the company do instead of cash the target audience is makes and famles aged zero and up. Can't you just take a picture from the internet? can you please send me the design specs again?, so can you help me out? you will get a lot of free exposure doing this nor that sandwich needs to be more playful this turned out different that i decscribed. We don't need a backup, it never goes down! can you lower the price for the website? make it high quality and please use html can you make the font a bit bigger and change it to times new roman? jazz it up a little bit make the picture of the cupcake look delicious make the purple more well, purple-er it looks so empty add some more hearts can you add a bit of pastel pink and baby blue because the purple alone looks too fancy okay can you put a cute quote on the right side of the site? oh no it looks messed up! i think we need to start from scratch.
|
||||
@@ -1,14 +0,0 @@
|
||||
Breathe in your fears. Face them. To conquer fear, you must become fear. You must bask in the fear of other men. And men fear most what they cannot see. You have to become a terrible thought. A wraith. You have to become an idea! Feel terror cloud your senses. Feel its power to distort. To control. And know that this power can be yours. Embrace your worst fear. Become one with the darkness.
|
||||
You wanna know how I got these scars? My father was... a drinker, and a fiend. And one night, he goes off crazier than usual. Mommy gets the kitchen knife to defend herself. He doesn't like that, not one bit. So, me watching he takes the knife to her, laughing while he does it. He turns to me and he says: "Why so serious?". He comes at me with the knife "Why so serious?". He sticks the blade in my mouth. "Let's put a smile on that face." and... Why so serious?
|
||||
My name is Merely Ducard but I speak for Ra's al Ghul... a man greatly feared by the criminal underworld. A mon who can offer you a path. Someone like you is only here by choice. You have been exploring the criminal fraternity but whatever your original intentions you have to become truly lost. The path of a man who shares his hatred of evil and wishes to serve true justice. The path of the League of Shadows.
|
||||
Every man who has lotted here over the centuries, has looked up to the light and imagined climbing to freedom. So easy, so simple! And like shipwrecked men turning to seawater foregoing uncontrollable thirst, many have died trying. And then here there can be no true despair without hope. So as I terrorize Gotham, I will feed its people hope to poison their souls. I will let them believe that they can survive so that you can watch them climbing over each other to stay in the sun. You can watch me torture an entire city. And then when you've truly understood the depth of your failure, we will fulfill Ra's Al Ghul's destiny. We will destroy Gotham. And then, when that is done, and Gotham is... ashes Then you have my permission to die.
|
||||
But we've met before. That was a long time ago, I was a kid at St. Swithin's, It used to be funded by the Wayne Foundation. It's an orphanage. My mum died when I was small, it was a car accident. I don't remember it. My dad got shot a couple of years later for a gambling debt. Oh I remember that one just fine. Not a lot of people know what it feels like to be angry in your bones. I mean they understand. The fosters parents. Everybody understands, for a while. Then they want the angry little kid to do something he knows he can't do, move on. After a while they stop understanding. They send the angry kid to a boy's home, I figured it out too late. Yeah I learned to hide the anger, and practice smiling in the mirror. It's like putting on a mask. So you showed up this one day, in a cool car, pretty girl on your arm. We were so excited! Bruce Wayne, a billionaire orphan? We used to make up stories about you man, legends and you know with the other kids, that's all it was, just stories, but right when I saw you, I knew who you really were. I'd seen that look on your face before. It's the same one I taught myself. I don't why you took the fault for Dent's murder but I'm still a believer in the Batman. Even if you're not...
|
||||
You wanna know how I got them? So I had a wife. She was beautiful, like you, who tells me I worry too much, who tells me I ought to smile more, who gambles and gets in deep with the sharks. Hey. One day they carve her face. And we have no money for surgeries. She can't take it. I just wanna see her smile again. I just want her to know that I don't care about the scars. So, I do this to myself. And you know what? She can't stand the sight of me. She leaves. Now I see the funny side. Now I'm always smiling.
|
||||
Every year, I took a holiday. I went to Florence, this cafe on the banks of the Arno. Every fine evening, I would sit there and order a Fernet Branca. I had this fantasy, that I would look across the tables and I would see you there with a wife maybe a couple of kids. You wouldn't say anything to me, nor me to you. But we would both know that you've made it, that you were happy. I never wanted you to come back to Gotham. I always knew there was nothing here for you except pain and tragedy and I wanted something more for you than that. I still do.
|
||||
Breathe in your fears. Face them. To conquer fear, you must become fear. You must bask in the fear of other men. And men fear most what they cannot see. You have to become a terrible thought. A wraith. You have to become an idea! Feel terror cloud your senses. Feel its power to distort. To control. And know that this power can be yours. Embrace your worst fear. Become one with the darkness.
|
||||
You wanna know how I got these scars? My father was... a drinker, and a fiend. And one night, he goes off crazier than usual. Mommy gets the kitchen knife to defend herself. He doesn't like that, not one bit. So, me watching he takes the knife to her, laughing while he does it. He turns to me and he says: "Why so serious?". He comes at me with the knife "Why so serious?". He sticks the blade in my mouth. "Let's put a smile on that face." and... Why so serious?
|
||||
My name is Merely Ducard but I speak for Ra's al Ghul... a man greatly feared by the criminal underworld. A mon who can offer you a path. Someone like you is only here by choice. You have been exploring the criminal fraternity but whatever your original intentions you have to become truly lost. The path of a man who shares his hatred of evil and wishes to serve true justice. The path of the League of Shadows.
|
||||
Every man who has lotted here over the centuries, has looked up to the light and imagined climbing to freedom. So easy, so simple! And like shipwrecked men turning to seawater foregoing uncontrollable thirst, many have died trying. And then here there can be no true despair without hope. So as I terrorize Gotham, I will feed its people hope to poison their souls. I will let them believe that they can survive so that you can watch them climbing over each other to stay in the sun. You can watch me torture an entire city. And then when you've truly understood the depth of your failure, we will fulfill Ra's Al Ghul's destiny. We will destroy Gotham. And then, when that is done, and Gotham is... ashes Then you have my permission to die.
|
||||
But we've met before. That was a long time ago, I was a kid at St. Swithin's, It used to be funded by the Wayne Foundation. It's an orphanage. My mum died when I was small, it was a car accident. I don't remember it. My dad got shot a couple of years later for a gambling debt. Oh I remember that one just fine. Not a lot of people know what it feels like to be angry in your bones. I mean they understand. The fosters parents. Everybody understands, for a while. Then they want the angry little kid to do something he knows he can't do, move on. After a while they stop understanding. They send the angry kid to a boy's home, I figured it out too late. Yeah I learned to hide the anger, and practice smiling in the mirror. It's like putting on a mask. So you showed up this one day, in a cool car, pretty girl on your arm. We were so excited! Bruce Wayne, a billionaire orphan? We used to make up stories about you man, legends and you know with the other kids, that's all it was, just stories, but right when I saw you, I knew who you really were. I'd seen that look on your face before. It's the same one I taught myself. I don't why you took the fault for Dent's murder but I'm still a believer in the Batman. Even if you're not...
|
||||
You wanna know how I got them? So I had a wife. She was beautiful, like you, who tells me I worry too much, who tells me I ought to smile more, who gambles and gets in deep with the sharks. Hey. One day they carve her face. And we have no money for surgeries. She can't take it. I just wanna see her smile again. I just want her to know that I don't care about the scars. So, I do this to myself. And you know what? She can't stand the sight of me. She leaves. Now I see the funny side. Now I'm always smiling.
|
||||
Every year, I took a holiday. I went to Florence, this cafe on the banks of the Arno. Every fine evening, I would sit there and order a Fernet Branca. I had this fantasy, that I would look across the tables and I would see you there with a wife maybe a couple of kids. You wouldn't say anything to me, nor me to you. But we would both know that you've made it, that you were happy. I never wanted you to come back to Gotham. I always knew there was nothing here for you except pain and tragedy and I wanted something more for you than that. I still do.
|
||||
@@ -1,207 +0,0 @@
|
||||
// Prints a file in the terminal separated by pages
|
||||
|
||||
#include "macro_collections.h"
|
||||
|
||||
#define TAB_SIZE 4
|
||||
#define ROW_INI_CAP DOC_LETTERS_IN_ROW
|
||||
#define DOC_LETTERS_IN_ROW 100
|
||||
#define DOC_ROWS_IN_PAGE 50
|
||||
#define DOC_MARGIN 4
|
||||
|
||||
C_MACRO_COLLECTIONS_ALL(CMC, LIST, (row, row, , , char))
|
||||
C_MACRO_COLLECTIONS_ALL(CMC, LIST, (doc, document, , , struct row *))
|
||||
|
||||
struct row_fval *row_funcs = &(struct row_fval){ NULL };
|
||||
struct document_fval *doc_funcs = &(struct document_fval){ .free = row_free };
|
||||
|
||||
struct document *document_load(const char *file_name);
|
||||
void document_empty_line(FILE *fptr);
|
||||
void document_page_outline(FILE *fptr, int outline);
|
||||
void document_page_margin(FILE *fptr, int margin);
|
||||
void document_print(struct document *doc, FILE *fptr);
|
||||
|
||||
struct document *document_load(const char *file_name)
|
||||
{
|
||||
FILE *file = fopen(file_name, "r");
|
||||
|
||||
if (!file)
|
||||
{
|
||||
cmc_log_error("File %s not found\n", file_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct row *initial_row = row_new(ROW_INI_CAP, row_funcs);
|
||||
|
||||
struct document *doc = doc_new(100, doc_funcs);
|
||||
doc_push_back(doc, initial_row);
|
||||
|
||||
int ch;
|
||||
|
||||
while ((ch = getc(file)) != EOF)
|
||||
{
|
||||
char c = (char)ch;
|
||||
|
||||
struct row *current_row = doc_back(doc);
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
struct row *new_row = row_new(ROW_INI_CAP, row_funcs);
|
||||
doc_push_back(doc, new_row);
|
||||
}
|
||||
else if (c == '\t')
|
||||
{
|
||||
intmax_t left = TAB_SIZE;
|
||||
|
||||
while (left > 0 && row_count(current_row) < DOC_LETTERS_IN_ROW)
|
||||
{
|
||||
row_push_back(current_row, ' ');
|
||||
left--;
|
||||
}
|
||||
|
||||
if (left > 0)
|
||||
{
|
||||
struct row *new_row = row_new(ROW_INI_CAP, row_funcs);
|
||||
doc_push_back(doc, new_row);
|
||||
|
||||
while (left > 0)
|
||||
{
|
||||
row_push_back(new_row, ' ');
|
||||
left--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (DOC_LETTERS_IN_ROW == row_count(current_row))
|
||||
{
|
||||
struct row *new_row = row_new(ROW_INI_CAP, row_funcs);
|
||||
row_push_back(new_row, c);
|
||||
doc_push_back(doc, new_row);
|
||||
}
|
||||
else
|
||||
row_push_back(current_row, c);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
void document_empty_line(FILE *fptr)
|
||||
{
|
||||
fputs("\t|", fptr);
|
||||
for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2; i++)
|
||||
{
|
||||
fputc(' ', fptr);
|
||||
}
|
||||
fputs("\t|\n", fptr);
|
||||
}
|
||||
|
||||
void document_page_outline(FILE *fptr, int outline /* 0 - header, 1 - footer */)
|
||||
{
|
||||
if (outline == 1)
|
||||
{
|
||||
document_empty_line(fptr);
|
||||
#ifdef DOC_PAGE_NUMBER
|
||||
static intmax_t page = 1;
|
||||
|
||||
fputs("\t|", fptr);
|
||||
for (size_t i = 0; i < (DOC_LETTERS_IN_ROW + DOC_MARGIN) - 8; i++)
|
||||
{
|
||||
fputc(' ', fptr);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%8" PRIdMAX "", page);
|
||||
page++;
|
||||
|
||||
document_page_margin(fptr, 1);
|
||||
document_empty_line(fptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
fputs("\t+", fptr);
|
||||
for (size_t i = 0; i < DOC_LETTERS_IN_ROW + DOC_MARGIN * 2 + 3; i++)
|
||||
{
|
||||
fputc('-', fptr);
|
||||
}
|
||||
fputs("+\n", fptr);
|
||||
|
||||
if (outline == 0)
|
||||
document_empty_line(fptr);
|
||||
}
|
||||
|
||||
void document_page_margin(FILE *fptr, int margin /* 0 - first margin, 1 - second margin */)
|
||||
{
|
||||
if (margin == 0)
|
||||
fputs("\t|", fptr);
|
||||
|
||||
for (size_t i = 0; i < DOC_MARGIN; i++)
|
||||
{
|
||||
fputc(' ', fptr);
|
||||
}
|
||||
|
||||
if (margin == 1)
|
||||
fputs("\t|\n", fptr);
|
||||
}
|
||||
|
||||
void document_print(struct document *doc, FILE *fptr)
|
||||
{
|
||||
fputc('\n', fptr);
|
||||
|
||||
intmax_t current_page_row = 0, total_rows = doc_count(doc);
|
||||
|
||||
// Print document
|
||||
for (intmax_t i = 0; i < total_rows; i++, current_page_row++)
|
||||
{
|
||||
if (current_page_row == 0)
|
||||
document_page_outline(fptr, 0);
|
||||
|
||||
struct row *current_row = doc_get(doc, i);
|
||||
|
||||
if (!current_row)
|
||||
cmc_log_fatal("Unexpected NULL pointer for %s", "current_row");
|
||||
|
||||
document_page_margin(fptr, 0);
|
||||
|
||||
for (size_t k = 0; k < row_count(current_row); k++)
|
||||
fputc(row_get(current_row, k), fptr);
|
||||
|
||||
// Trailing margin
|
||||
for (size_t k = 0; k < DOC_LETTERS_IN_ROW - row_count(current_row); k++)
|
||||
fputc(' ', fptr);
|
||||
|
||||
document_page_margin(fptr, 1);
|
||||
|
||||
// Print the end of the page and reset
|
||||
if (current_page_row == DOC_ROWS_IN_PAGE - 1)
|
||||
{
|
||||
document_page_outline(fptr, 1);
|
||||
current_page_row = -1;
|
||||
fputc('\n', fptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Print trailing page
|
||||
if (total_rows % DOC_ROWS_IN_PAGE != 0)
|
||||
{
|
||||
for (size_t i = 0; i < DOC_ROWS_IN_PAGE - current_page_row; i++)
|
||||
document_empty_line(fptr);
|
||||
|
||||
document_page_outline(fptr, 1);
|
||||
}
|
||||
|
||||
fputc('\n', fptr);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
cmc_log_error("Please define one argument only for %s", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct document *doc = document_load(argv[1]);
|
||||
|
||||
document_print(doc, stdout);
|
||||
|
||||
doc_free(doc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Queue examples
|
||||
|
||||
* ice_cream.c - Example of what happens when you get late to the queue and the ice creams are sold out!
|
||||
* iterator.c - A complete example of the queue iterator
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* ice_cream.c
|
||||
*
|
||||
* Creation Date: 03/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/queue.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
CMC_GENERATE_QUEUE(q, queue, const char *);
|
||||
typedef struct queue queue;
|
||||
typedef struct queue_iter queue_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
srand((unsigned)time(NULL));
|
||||
|
||||
// 1- People are lining up to get some ice cream but there is not enough
|
||||
// for everyone! Hurry! Get in the queue!
|
||||
|
||||
size_t total_icecreams = 20;
|
||||
|
||||
queue *lineup = q_new(10);
|
||||
|
||||
q_enqueue(lineup, "Albert");
|
||||
q_enqueue(lineup, "Newton");
|
||||
q_enqueue(lineup, "Marie");
|
||||
q_enqueue(lineup, "Charles");
|
||||
q_enqueue(lineup, "Nikola");
|
||||
q_enqueue(lineup, "Thomas");
|
||||
q_enqueue(lineup, "Niels");
|
||||
q_enqueue(lineup, "Galileo");
|
||||
q_enqueue(lineup, "Stephen");
|
||||
q_enqueue(lineup, "Leonardo");
|
||||
q_enqueue(lineup, "Max");
|
||||
q_enqueue(lineup, "Dmitri");
|
||||
|
||||
while (total_icecreams > 0)
|
||||
{
|
||||
size_t catch = rand() % 5;
|
||||
|
||||
const char *name = q_peek(lineup);
|
||||
|
||||
if (!q_dequeue(lineup))
|
||||
break;
|
||||
|
||||
printf("%-8s got %lu ice cream(s) from the ice cream truck\n", name, catch);
|
||||
|
||||
total_icecreams = catch > total_icecreams ? 0 : total_icecreams - catch;
|
||||
}
|
||||
|
||||
if (!q_empty(lineup))
|
||||
{
|
||||
printf("\nOh no! Someone didn't get their ice cream!\n\n");
|
||||
|
||||
while (!q_empty(lineup))
|
||||
{
|
||||
const char *name = q_peek(lineup);
|
||||
|
||||
q_dequeue(lineup);
|
||||
|
||||
printf("%-8s got no ice cream and he is sad\n", name);
|
||||
}
|
||||
}
|
||||
else if (total_icecreams > 0)
|
||||
{
|
||||
printf("\n%lu ice creams remaining to be sold on the next day.\n");
|
||||
}
|
||||
|
||||
q_free(lineup, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/queue.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a queue of integers
|
||||
CMC_GENERATE_QUEUE(q, queue, int);
|
||||
typedef struct queue queue;
|
||||
typedef struct queue_iter queue_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new queue with an initial capacity of 100
|
||||
queue *my_queue = q_new(100);
|
||||
|
||||
// Add elements to the queue
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
q_enqueue(my_queue, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (front) to the end (rear) of the queue
|
||||
for (queue_iter it = my_queue->it_start(my_queue); // Initialize iterator 'it' to the start of the queue
|
||||
!q_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
q_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = q_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
// Print queue
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == q_count(my_queue) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = q_count(my_queue) / 2;
|
||||
for (queue_iter it = my_queue->it_start(my_queue); !q_iter_end(&it); q_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = q_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
// Print queue up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the queue
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (queue_iter it = my_queue->it_end(my_queue); // Initialize iterator 'it' to the end of the queue
|
||||
!q_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
q_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = q_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
// Print queue
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == q_count(my_queue) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
queue_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the queue [ my_queue->it_start() and my_queue->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_queue->it_start(my_queue);
|
||||
it = my_queue->it_end(my_queue);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
q_iter_init(&it, my_queue);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
queue_iter *iter = q_iter_new(my_queue);
|
||||
|
||||
// The actual while loop
|
||||
while (!q_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = q_iter_value(iter);
|
||||
size_t i = q_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("queue[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
q_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the queue
|
||||
q_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the queue
|
||||
q_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!q_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = q_iter_value(iter);
|
||||
size_t i = q_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("queue[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
q_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 3 to the number 7
|
||||
for (q_iter_to_start(&it); !q_iter_end(&it); q_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = q_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 3 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (queue_iter it = my_queue->it_start(my_queue); !q_iter_end(&it); q_iter_next(&it))
|
||||
{
|
||||
int e = q_iter_value(&it);
|
||||
size_t i = q_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == q_count(my_queue) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by q_iter_new()
|
||||
q_iter_free(iter);
|
||||
// Dispose the queue created
|
||||
q_free(my_queue, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "cmc/bitset.h"
|
||||
#include <math.h>
|
||||
|
||||
CMC_CMC_BITSET_CORE(PUBLIC, HEADER, (bs, bitset))
|
||||
CMC_CMC_BITSET_CORE(PUBLIC, SOURCE, (bs, bitset))
|
||||
|
||||
// All the prime numbers up to 1 billion
|
||||
// With -O3:
|
||||
// 28.583 s runtime
|
||||
// 120 MB RAM
|
||||
// 490 MB file size
|
||||
int main(void)
|
||||
{
|
||||
const size_t n = 1000000000;
|
||||
|
||||
struct bitset *set = bs_new(n);
|
||||
|
||||
if (!set)
|
||||
return 1;
|
||||
|
||||
bs_set_range(set, 0, n);
|
||||
|
||||
size_t up_to = sqrt((double)n) + 1;
|
||||
for (size_t i = 2; i < up_to; ++i)
|
||||
{
|
||||
if (bs_get(set, i))
|
||||
{
|
||||
for (size_t j = 2 * i; j < n; j += i)
|
||||
bs_clear(set, j);
|
||||
}
|
||||
}
|
||||
|
||||
FILE *file = fopen("primes.txt", "w");
|
||||
|
||||
for (size_t i = 2; i < n; i++)
|
||||
{
|
||||
if (bs_get(set, i))
|
||||
fprintf(file, "%" PRIuMAX " ", i);
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Stack examples
|
||||
|
||||
* hanoi.c - Animated example of solving the hanoi tower.
|
||||
* iterator.c - A complete example of the stack iterator
|
||||
@@ -1,111 +0,0 @@
|
||||
/**
|
||||
* hanoi.c
|
||||
*
|
||||
* Creation Date: 03/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/stack.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
CMC_GENERATE_STACK(s, stack, int);
|
||||
typedef struct stack stack;
|
||||
typedef struct stack_iter stack_iter;
|
||||
|
||||
|
||||
void print_hanoi(stack *t1, stack *t2, stack *t3);
|
||||
const char *draw(int value);
|
||||
void move_disc(stack *from, stack *to);
|
||||
void move_stack(stack *t1, stack *t2, stack *t3, size_t size);
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// 1- Hanoi towers showcase
|
||||
|
||||
stack *tower1 = s_new(10);
|
||||
stack *tower2 = s_new(10);
|
||||
stack *tower3 = s_new(10);
|
||||
|
||||
for (int i = 10; i > 0; i--)
|
||||
s_push(tower1, i);
|
||||
|
||||
move_stack(tower1, tower3, tower2, s_count(tower1));
|
||||
|
||||
s_free(tower1, NULL);
|
||||
s_free(tower2, NULL);
|
||||
s_free(tower3, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_hanoi(stack *t1, stack *t2, stack *t3)
|
||||
{
|
||||
const int max = 10;
|
||||
|
||||
static int step = 0;
|
||||
printf("Step %d\n", ++step);
|
||||
|
||||
for (int i = max - 1; i >= 0; i--)
|
||||
{
|
||||
|
||||
printf(" %10s|%-10s %10s|%-10s %10s|%-10s\n",
|
||||
draw(t1->buffer[i]), draw(t1->buffer[i]),
|
||||
draw(t2->buffer[i]), draw(t2->buffer[i]),
|
||||
draw(t3->buffer[i]), draw(t3->buffer[i]));
|
||||
}
|
||||
printf(" ----------------------- ----------------------- -----------------------\n\n");
|
||||
}
|
||||
|
||||
const char *draw(int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
return "";
|
||||
case 1:
|
||||
return "#";
|
||||
case 2:
|
||||
return "##";
|
||||
case 3:
|
||||
return "###";
|
||||
case 4:
|
||||
return "####";
|
||||
case 5:
|
||||
return "#####";
|
||||
case 6:
|
||||
return "######";
|
||||
case 7:
|
||||
return "#######";
|
||||
case 8:
|
||||
return "########";
|
||||
case 9:
|
||||
return "#########";
|
||||
case 10:
|
||||
return "##########";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
void move_disc(stack *from, stack *to)
|
||||
{
|
||||
s_push(to, s_top(from));
|
||||
s_pop(from);
|
||||
}
|
||||
|
||||
void move_stack(stack *t1, stack *t2, stack *t3, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
move_stack(t1, t3, t2, size - 1);
|
||||
|
||||
move_disc(t1, t2);
|
||||
|
||||
print_hanoi(t1, t2, t3);
|
||||
|
||||
move_stack(t3, t2, t1, size - 1);
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 15/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/stack.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Creates a stack of integers
|
||||
CMC_GENERATE_STACK(s, stack, int);
|
||||
typedef struct stack stack;
|
||||
typedef struct stack_iter stack_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new stack with an initial capacity of 100
|
||||
stack *my_stack = s_new(100);
|
||||
|
||||
// Add elements to the stack
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
s_push(my_stack, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (top) to the end (bottom) of the stack
|
||||
for (stack_iter it = my_stack->it_start(my_stack); // Initialize iterator 'it' to the start of the stack
|
||||
!s_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
s_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = s_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
// Print stack
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == s_count(my_stack) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = s_count(my_stack) / 2;
|
||||
for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = s_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
// Print stack up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the stack
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (stack_iter it = my_stack->it_end(my_stack); // Initialize iterator 'it' to the end of the stack
|
||||
!s_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
s_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = s_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
// Print stack
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == s_count(my_stack) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
stack_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the stack [ my_stack->it_start() and my_stack->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_stack->it_start(my_stack);
|
||||
it = my_stack->it_end(my_stack);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
s_iter_init(&it, my_stack);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
stack_iter *iter = s_iter_new(my_stack);
|
||||
|
||||
// The actual while loop
|
||||
while (!s_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = s_iter_value(iter);
|
||||
size_t i = s_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("stack[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
s_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the stack
|
||||
s_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the stack
|
||||
s_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!s_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = s_iter_value(iter);
|
||||
size_t i = s_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("stack[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
s_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every element that is divisible by 3 to the number 7
|
||||
for (s_iter_to_start(&it); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
// Get a reference to the current value
|
||||
int *r = s_iter_rvalue(&it);
|
||||
|
||||
if (r != NULL && *r % 3 == 0)
|
||||
*r = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (stack_iter it = my_stack->it_start(my_stack); !s_iter_end(&it); s_iter_next(&it))
|
||||
{
|
||||
int e = s_iter_value(&it);
|
||||
size_t i = s_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
else if (i == s_count(my_stack) - 1)
|
||||
printf("%d ]\n", e);
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by s_iter_new()
|
||||
s_iter_free(iter);
|
||||
// Dispose the stack created
|
||||
s_free(my_stack, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
# Treemap examples
|
||||
|
||||
* pseudo_multiset.c - An example of how to make a multiset using a map.
|
||||
* iterator.c - A complete example of the treemap iterator
|
||||
@@ -1,220 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 16/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/treemap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a treemap of integers
|
||||
CMC_GENERATE_TREEMAP(tm, treemap, int, double);
|
||||
typedef struct treemap treemap;
|
||||
typedef struct treemap_iter treemap_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new treemap
|
||||
treemap *my_map = tm_new(intcmp);
|
||||
|
||||
// Add pairs to the treemap
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
// Map integers to doubles
|
||||
tm_insert(my_map, i, (double)i / 10.0);
|
||||
}
|
||||
|
||||
// Iterate from the start (left-most node) to the end (right-most node) of the treemap
|
||||
for (treemap_iter it = my_map->it_start(my_map); // Initialize iterator 'it' to the start of the treemap
|
||||
!tm_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
tm_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = tm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
// Print treemap
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == tm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = tm_count(my_map) / 2;
|
||||
for (treemap_iter it = my_map->it_start(my_map); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
// Access the current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = tm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
// Print treemap up until limit
|
||||
|
||||
// If it is the first pair
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the treemap
|
||||
{
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
break;
|
||||
}
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (treemap_iter it = my_map->it_end(my_map); // Initialize iterator 'it' to the end of the treemap
|
||||
!tm_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
tm_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Access the current value
|
||||
double v = tm_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the pairs in the iteration)
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
// Print treemap
|
||||
// Note how the conditions for the first and last pairs are simply swapped
|
||||
// Because iterating backwards make the first pair be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first pair
|
||||
if (i == tm_count(my_map) - 1)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
// If it is the last pair
|
||||
else if (i == 0)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
// For pairs at the middle
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
treemap_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the treemap [ my_map->it_start() and my_map->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_map->it_start(my_map);
|
||||
it = my_map->it_end(my_map);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
tm_iter_init(&it, my_map);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
treemap_iter *iter = tm_iter_new(my_map);
|
||||
|
||||
// The actual while loop
|
||||
while (!tm_iter_end(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = tm_iter_key(iter);
|
||||
double v = tm_iter_value(iter);
|
||||
size_t i = tm_iter_index(iter);
|
||||
|
||||
// Print index and key value pair
|
||||
printf("treemap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator forwards
|
||||
tm_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the treemap
|
||||
tm_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the treemap
|
||||
tm_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!tm_iter_start(iter))
|
||||
{
|
||||
// Accessing pairs
|
||||
int k = tm_iter_key(iter);
|
||||
double v = tm_iter_value(iter);
|
||||
size_t i = tm_iter_index(iter);
|
||||
|
||||
// Print index and the key value pair
|
||||
printf("treemap[%2" PRIuMAX "] = { %2d : %.2lf }\n", i, k, v);
|
||||
|
||||
// Move iterator backwards
|
||||
tm_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the pair
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// Change every value where its key is divisible by 3 to the number 7
|
||||
for (tm_iter_to_start(&it); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
// Get current key
|
||||
int k = tm_iter_key(&it);
|
||||
|
||||
// Get a reference to the current value
|
||||
double *v = tm_iter_rvalue(&it);
|
||||
|
||||
if (k % 3 == 0)
|
||||
*v = 7;
|
||||
}
|
||||
|
||||
// Now print it to see the difference
|
||||
for (treemap_iter it = my_map->it_start(my_map); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
int k = tm_iter_key(&it);
|
||||
double v = tm_iter_value(&it);
|
||||
size_t i = tm_iter_index(&it);
|
||||
|
||||
if (i == 0)
|
||||
printf("[ {%d:%.2lf}, ", k, v);
|
||||
else if (i == tm_count(my_map) - 1)
|
||||
printf("{%d:%.2lf} ]\n", k, v);
|
||||
else
|
||||
printf("{%d:%.2lf}, ", k, v);
|
||||
}
|
||||
|
||||
// Dispose the iterator called by tm_iter_new()
|
||||
tm_iter_free(iter);
|
||||
// Dispose the treemap created
|
||||
tm_free(my_map, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/**
|
||||
* pseudo_multiset.c
|
||||
*
|
||||
* Creation Date: 26/04/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
// How to make a multiset using a map
|
||||
|
||||
#include "cmc/treemap.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Mapping an integer by size_t which will represent the key's multiplicity
|
||||
// (key could be anything and multiplicity could be an integer, preferably
|
||||
// unsigned)
|
||||
CMC_GENERATE_TREEMAP(tm, tmap, int, size_t);
|
||||
typedef struct tmap tmap;
|
||||
typedef struct tmap_iter tmap_iter;
|
||||
typedef struct tmap_node tmap_node;
|
||||
|
||||
|
||||
// Compare function used by the treemap
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
// Little helper to print the tree
|
||||
void print_tree(tmap_node *root, int height)
|
||||
{
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
print_tree(root->right, height + 1);
|
||||
|
||||
for (int i = 0; i < height; i++)
|
||||
printf("|------- ");
|
||||
|
||||
// Key:Multiplicity
|
||||
printf("%d:%" PRIuMAX "\n", root->key, root->value);
|
||||
|
||||
print_tree(root->left, height + 1);
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
tmap *map = tm_new(intcmp);
|
||||
|
||||
// Start adding elements
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
// Modulo of 8 so we get some repetition
|
||||
int key = i % 8;
|
||||
|
||||
// Get the reference to a value in the map with the key
|
||||
size_t *rvalue = tm_get_ref(map, key);
|
||||
|
||||
// If the key exists, rvalue is not null
|
||||
if (rvalue != NULL)
|
||||
{
|
||||
// Incrementing it means we have added another key to the set
|
||||
// The value represents the multiplicity, that is, how many times
|
||||
// we have added the key in the set
|
||||
(*rvalue)++;
|
||||
}
|
||||
else
|
||||
// Create a new entry with key with an initial multiplicity of 1
|
||||
tm_insert(map, key, 1);
|
||||
}
|
||||
|
||||
print_tree(map->root, 0);
|
||||
|
||||
// Summary
|
||||
printf("\n---------- SUMMARY ----------\n\n");
|
||||
|
||||
// Print using iterator
|
||||
for (tmap_iter it = map->it_start(map); !tm_iter_end(&it); tm_iter_next(&it))
|
||||
{
|
||||
// Map[key] = multiplicity
|
||||
printf("Map[%2d] = %" PRIuMAX "\n", tm_iter_key(&it), tm_iter_value(&it));
|
||||
}
|
||||
|
||||
tm_free(map, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
# Treeset examples
|
||||
|
||||
* iterator.c - A complete example of the treeset iterator
|
||||
* set_ops.c - Demonstrates common set operations like *union*, *intersection*, *difference* and *symmetric difference*.
|
||||
* tree_print.c - How to print a binary tree.
|
||||
@@ -1,197 +0,0 @@
|
||||
/**
|
||||
* iterator.c
|
||||
*
|
||||
* Creation Date: 16/05/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
* Iterator Example
|
||||
*/
|
||||
#include "cmc/treeset.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
// Int hash function
|
||||
size_t inthash(int t)
|
||||
{
|
||||
size_t a = t;
|
||||
a += ~(a << 15);
|
||||
a ^= (a >> 10);
|
||||
a += (a << 3);
|
||||
a ^= (a >> 6);
|
||||
a += ~(a << 11);
|
||||
a ^= (a >> 16);
|
||||
return a;
|
||||
}
|
||||
|
||||
// Int compare function
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Creates a treeset of integers
|
||||
CMC_GENERATE_TREESET(ts, treeset, int);
|
||||
typedef struct treeset treeset;
|
||||
typedef struct treeset_iter treeset_iter;
|
||||
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
// Create a new treeset with an initial capacity of 100 and load factor of 0.6
|
||||
treeset *my_treeset = ts_new(intcmp);
|
||||
|
||||
// Add elements to the treeset
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
ts_insert(my_treeset, i);
|
||||
}
|
||||
|
||||
// Iterate from the start (index 0) to the end (index count - 1) of the treeset
|
||||
for (treeset_iter it = my_treeset->it_start(my_treeset); // Initialize iterator 'it' to the start of the treeset
|
||||
!ts_iter_end(&it); // Conditional stop (until it is not at the end)
|
||||
ts_iter_next(&it)) // Iterator goes one position forward
|
||||
{
|
||||
// Access the current element
|
||||
int e = ts_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ts_iter_index(&it);
|
||||
|
||||
// Print treeset
|
||||
|
||||
// Index is useful in situations like this
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == ts_count(my_treeset) - 1)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Index can also be used to iterate over a certain portion of a collection
|
||||
size_t limit = ts_count(my_treeset) / 2;
|
||||
for (treeset_iter it = my_treeset->it_start(my_treeset); !ts_iter_end(&it); ts_iter_next(&it))
|
||||
{
|
||||
// Access the current element
|
||||
int e = ts_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ts_iter_index(&it);
|
||||
|
||||
// Print treeset up until limit
|
||||
|
||||
// If it is the first element
|
||||
if (i == 0)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == limit - 1) // -1 because index is 0 based and we want half of the treeset
|
||||
{
|
||||
printf("%d ]\n", e);
|
||||
break;
|
||||
}
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// Going backwards
|
||||
for (treeset_iter it = my_treeset->it_end(my_treeset); // Initialize iterator 'it' to the end of the treeset
|
||||
!ts_iter_start(&it); // Conditional stop (until it is not at the start)
|
||||
ts_iter_prev(&it)) // Iterator goes one position backwards
|
||||
{
|
||||
// Access the current element
|
||||
int e = ts_iter_value(&it);
|
||||
|
||||
// Access the current index (index is relative to all the elements in the iteration)
|
||||
size_t i = ts_iter_index(&it);
|
||||
|
||||
// Print treeset
|
||||
// Note how the conditions for the first and last elements are simply swapped
|
||||
// Because iterating backwards make the first element be the index count - 1
|
||||
// and the last one be the index 0
|
||||
|
||||
// If it is the first element
|
||||
if (i == ts_count(my_treeset) - 1)
|
||||
printf("[ %d, ", e);
|
||||
// If it is the last element
|
||||
else if (i == 0)
|
||||
printf("%d ]\n", e);
|
||||
// For elements at the middle
|
||||
else
|
||||
printf("%d, ", e);
|
||||
}
|
||||
|
||||
// You can also use iterators in a while loop
|
||||
// But to do so you must declare the iterator struct outside the loop first
|
||||
treeset_iter it;
|
||||
|
||||
// You have three options:
|
||||
// - Initialize it using the functions provided by the treeset [ my_treeset->it_start() and my_treeset->it_end() ]
|
||||
// - Initialize it using the init() function (when the iterator is already allocated)
|
||||
// - Initialize it using the new() function (allocates on the heap, pointers only)
|
||||
|
||||
it = my_treeset->it_start(my_treeset);
|
||||
it = my_treeset->it_end(my_treeset);
|
||||
|
||||
// This is equivalent to it_start()
|
||||
ts_iter_init(&it, my_treeset);
|
||||
|
||||
// For pointers
|
||||
// Also equivalent to it_start()
|
||||
treeset_iter *iter = ts_iter_new(my_treeset);
|
||||
|
||||
// The actual while loop
|
||||
while (!ts_iter_end(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ts_iter_value(iter);
|
||||
size_t i = ts_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("treeset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator forwards
|
||||
ts_iter_next(iter);
|
||||
}
|
||||
|
||||
// Send the iterator to the start of the treeset
|
||||
ts_iter_to_start(iter);
|
||||
|
||||
// Send the iterator to the end of the treeset
|
||||
ts_iter_to_end(iter);
|
||||
|
||||
// Backwards loop
|
||||
while (!ts_iter_start(iter))
|
||||
{
|
||||
// Accessing elements
|
||||
int e = ts_iter_value(iter);
|
||||
size_t i = ts_iter_index(iter);
|
||||
|
||||
// Print index and element
|
||||
printf("treeset[%2" PRIuMAX "] = %2d\n", i, e);
|
||||
|
||||
// Move iterator backwards
|
||||
ts_iter_prev(iter);
|
||||
}
|
||||
|
||||
// Certain iterators also allow you to modify the contents it is iterating over
|
||||
// Exceptions are collections that depend of the current state of the element
|
||||
// like tree-based collections and heap (collections that have some kind of ordering).
|
||||
// You also can't change the keys of an associative collection
|
||||
|
||||
// In the case of a treeset or any set, this is not possible because the
|
||||
// values of a set are its keys. Changing the elements could cause the set
|
||||
// to be in an invalid state.
|
||||
|
||||
// Dispose the iterator called by ts_iter_new()
|
||||
ts_iter_free(iter);
|
||||
// Dispose the treeset created
|
||||
ts_free(my_treeset, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* set_ops.c
|
||||
*
|
||||
* Creation Date: 27/03/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
|
||||
// Demonstration of set operations like:
|
||||
// - Union
|
||||
// - Intersection
|
||||
// - Difference
|
||||
// - Symmetric Difference
|
||||
|
||||
#include "cmc/treeset.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
CMC_GENERATE_TREESET(set, set, int);
|
||||
typedef struct set set;
|
||||
typedef struct set_iter set_iter;
|
||||
|
||||
|
||||
void print_set(set *s)
|
||||
{
|
||||
set_iter iter;
|
||||
set_iter_init(&iter, s);
|
||||
for (set_iter_to_start(&iter); !set_iter_end(&iter); set_iter_next(&iter))
|
||||
{
|
||||
int result = set_iter_value(&iter);
|
||||
size_t index = set_iter_index(&iter);
|
||||
|
||||
if (index == 0)
|
||||
printf("[ %2d, ", result);
|
||||
else if (index == s->count - 1)
|
||||
printf("%2d ]\n", result);
|
||||
else
|
||||
printf("%2d, ", result);
|
||||
}
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
set *set1 = set_new(intcmp);
|
||||
set *set2 = set_new(intcmp);
|
||||
|
||||
for (int i = 1; i <= 20; i++)
|
||||
set_insert(set1, i);
|
||||
|
||||
for (int i = 11; i <= 30; i++)
|
||||
set_insert(set2, i);
|
||||
|
||||
set *set3 = set_union(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("UNION\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set3);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
set *set4 = set_intersection(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("INTERSECTION\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set4);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
set *set5 = set_difference(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("DIFFERENCE\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set5);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
set *set6 = set_symmetric_difference(set1, set2);
|
||||
|
||||
print_set(set1);
|
||||
printf("SYMMETRIC DIFFERENCE\n");
|
||||
print_set(set2);
|
||||
printf("=\n");
|
||||
print_set(set6);
|
||||
|
||||
set_free(set1, NULL);
|
||||
set_free(set2, NULL);
|
||||
set_free(set3, NULL);
|
||||
set_free(set4, NULL);
|
||||
set_free(set5, NULL);
|
||||
set_free(set6, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
/**
|
||||
* tree_print.c
|
||||
*
|
||||
* Creation Date: 27/03/2019
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
*
|
||||
*/
|
||||
#include "cmc/treeset.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
CMC_GENERATE_TREESET(set, set, int);
|
||||
typedef struct set set;
|
||||
typedef struct set_iter set_iter;
|
||||
typedef struct set_node set_node;
|
||||
|
||||
|
||||
void print_tree(set_node *root, int height)
|
||||
{
|
||||
if (!root)
|
||||
return;
|
||||
|
||||
print_tree(root->right, height + 1);
|
||||
|
||||
for (int i = 0; i < height; i++)
|
||||
printf("|------- ");
|
||||
|
||||
printf("%d\n", root->value);
|
||||
|
||||
print_tree(root->left, height + 1);
|
||||
}
|
||||
|
||||
int intcmp(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
|
||||
int main(int argc, char const *argv[])
|
||||
{
|
||||
set *set1 = set_new(intcmp);
|
||||
|
||||
for (int i = 0; i < 31; i++)
|
||||
{
|
||||
set_insert(set1, i);
|
||||
}
|
||||
|
||||
print_tree(set1->root, 0);
|
||||
|
||||
set_free(set1, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,382 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
/* None */
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_deque_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_deque_)
|
||||
return NULL;
|
||||
|
||||
_deque_->buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_deque_->buffer)
|
||||
{
|
||||
alloc->free(_deque_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_deque_->capacity = capacity;
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
_deque_->f_val = f_val;
|
||||
_deque_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
|
||||
|
||||
return _deque_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_deque_)
|
||||
{
|
||||
if (_deque_->f_val->free)
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
_deque_->f_val->free(_deque_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
memset(_deque_->buffer, 0, sizeof(V) * _deque_->capacity);
|
||||
|
||||
_deque_->count = 0;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = 0;
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_deque_)
|
||||
{
|
||||
if (_deque_->f_val->free)
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
_deque_->f_val->free(_deque_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
_deque_->alloc->free(_deque_->buffer);
|
||||
_deque_->alloc->free(_deque_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_deque_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_deque_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_deque_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_deque_, callbacks);
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_deque_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->front = (_deque_->front == 0) ? _deque_->capacity - 1 : _deque_->front - 1;
|
||||
|
||||
_deque_->buffer[_deque_->front] = value;
|
||||
|
||||
_deque_->count++;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_deque_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_deque_, _deque_->capacity * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->buffer[_deque_->back] = value;
|
||||
|
||||
_deque_->back = (_deque_->back == _deque_->capacity - 1) ? 0 : _deque_->back + 1;
|
||||
|
||||
_deque_->count++;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->buffer[_deque_->front] = (V){ 0 };
|
||||
|
||||
_deque_->front = (_deque_->front == _deque_->capacity - 1) ? 0 : _deque_->front + 1;
|
||||
|
||||
_deque_->count--;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
_deque_->back = (_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1;
|
||||
|
||||
_deque_->buffer[_deque_->back] = (V){ 0 };
|
||||
|
||||
_deque_->count--;
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _front)(struct SNAME *_deque_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, read);
|
||||
|
||||
return _deque_->buffer[_deque_->front];
|
||||
}
|
||||
|
||||
V CMC_(PFX, _back)(struct SNAME *_deque_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_deque_))
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, read);
|
||||
|
||||
return _deque_->buffer[(_deque_->back == 0) ? _deque_->capacity - 1 : _deque_->back - 1];
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
if (_deque_->f_val->cmp(_deque_->buffer[i], value) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_deque_)
|
||||
{
|
||||
return _deque_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_deque_)
|
||||
{
|
||||
return _deque_->count >= _deque_->capacity;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_deque_)
|
||||
{
|
||||
return _deque_->count;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_)
|
||||
{
|
||||
return _deque_->capacity;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_deque_)
|
||||
{
|
||||
return _deque_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_deque_->capacity == capacity)
|
||||
goto success;
|
||||
|
||||
if (capacity < _deque_->count)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
V *new_buffer = _deque_->alloc->malloc(sizeof(V) * capacity);
|
||||
|
||||
if (!new_buffer)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
new_buffer[j] = _deque_->buffer[i];
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
|
||||
_deque_->alloc->free(_deque_->buffer);
|
||||
|
||||
_deque_->buffer = new_buffer;
|
||||
_deque_->capacity = capacity;
|
||||
_deque_->front = 0;
|
||||
_deque_->back = _deque_->count;
|
||||
|
||||
success:
|
||||
|
||||
CMC_CALLBACKS_CALL(_deque_, resize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_)
|
||||
{
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_deque_->capacity, _deque_->f_val, _deque_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_deque_->flag = CMC_FLAG_ERROR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _deque_->callbacks);
|
||||
|
||||
if (_deque_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
result->buffer[j] = _deque_->f_val->cpy(_deque_->buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
result->buffer[j] = _deque_->buffer[i];
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
}
|
||||
}
|
||||
|
||||
result->count = _deque_->count;
|
||||
result->front = 0;
|
||||
result->back = _deque_->count;
|
||||
|
||||
_deque_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_)
|
||||
{
|
||||
_deque1_->flag = CMC_FLAG_OK;
|
||||
_deque2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_deque1_->count != _deque2_->count)
|
||||
return false;
|
||||
|
||||
size_t i, j, k;
|
||||
for (i = _deque1_->front, j = _deque2_->front, k = 0; k < _deque1_->count; k++)
|
||||
{
|
||||
if (_deque1_->f_val->cmp(_deque1_->buffer[i], _deque2_->buffer[j]) != 0)
|
||||
return false;
|
||||
|
||||
i = (i + 1) % _deque1_->capacity;
|
||||
j = (j + 1) % _deque2_->capacity;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _init_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _deque_ = { 0 };
|
||||
|
||||
if (capacity < 1)
|
||||
return _deque_;
|
||||
|
||||
if (!f_val)
|
||||
return _deque_;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_deque_.buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_deque_.buffer)
|
||||
return _deque_;
|
||||
|
||||
_deque_.capacity = capacity;
|
||||
_deque_.count = 0;
|
||||
_deque_.front = 0;
|
||||
_deque_.back = 0;
|
||||
_deque_.flag = CMC_FLAG_OK;
|
||||
_deque_.f_val = f_val;
|
||||
_deque_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_deque_, callbacks);
|
||||
|
||||
return _deque_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _deque_)
|
||||
{
|
||||
if (_deque_.f_val->free)
|
||||
{
|
||||
for (size_t i = _deque_.front, j = 0; j < _deque_.count; j++)
|
||||
{
|
||||
_deque_.f_val->free(_deque_.buffer[i]);
|
||||
|
||||
i = (i + 1) % _deque_.capacity;
|
||||
}
|
||||
}
|
||||
|
||||
_deque_.alloc->free(_deque_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_DEQUE_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Deque bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = target->front;
|
||||
iter.index = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
{
|
||||
if (iter.target->back == 0)
|
||||
iter.cursor = iter.target->capacity - 1;
|
||||
else
|
||||
iter.cursor = iter.target->back - 1;
|
||||
|
||||
iter.index = iter.target->count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter.cursor = 0;
|
||||
iter.index = 0;
|
||||
}
|
||||
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = iter->target->front;
|
||||
iter->index = 0;
|
||||
iter->start = true;
|
||||
iter->end = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
if (iter->target->back == 0)
|
||||
iter->cursor = iter->target->capacity - 1;
|
||||
else
|
||||
iter->cursor = iter->target->back - 1;
|
||||
|
||||
iter->index = iter->target->count - 1;
|
||||
|
||||
iter->start = false;
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = (iter->cursor + 1) % (iter->target->capacity);
|
||||
iter->index++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor = (iter->cursor == 0) ? iter->target->capacity - 1 : iter->cursor - 1;
|
||||
iter->index--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->index + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index += steps;
|
||||
iter->cursor = (iter->cursor + steps) % iter->target->capacity;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->index == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->index < steps)
|
||||
return false;
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->index -= steps;
|
||||
|
||||
/* Prevent underflow */
|
||||
if (iter->cursor < steps)
|
||||
iter->cursor += iter->target->capacity;
|
||||
|
||||
iter->cursor -= steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->index > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->index - index);
|
||||
else if (iter->index < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->index);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return iter->index;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_DEQUE_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr)
|
||||
{
|
||||
struct SNAME *d_ = _deque_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"front:%" PRIuMAX ", "
|
||||
"back:%" PRIuMAX ", "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), d_, d_->buffer, d_->capacity, d_->count, d_->front,
|
||||
d_->back, d_->flag, d_->f_val, d_->alloc, CMC_CALLBACKS_GET(d_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
for (size_t i = _deque_->front, j = 0; j < _deque_->count; j++)
|
||||
{
|
||||
if (!_deque_->f_val->str(fptr, _deque_->buffer[i]))
|
||||
return false;
|
||||
|
||||
i = (i + 1) % _deque_->capacity;
|
||||
|
||||
if (j + 1 < _deque_->count)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_DEQUE_STR */
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _deque_);
|
||||
|
||||
#endif /* CMC_EXT_DEQUE_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Deque bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_DEQUE_ITER */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_STR
|
||||
|
||||
/* Debug prints the struct to fptr */
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_deque_, FILE *fptr);
|
||||
/* Prints each item in the deque as an array */
|
||||
bool CMC_(PFX, _print)(struct SNAME *_deque_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_DEQUE_STR */
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* Deque bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_ITER
|
||||
|
||||
/* Deque Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target deque */
|
||||
struct SNAME *target;
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
/* Keeps track of relative index to the iteration of elements */
|
||||
size_t index;
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#endif /* CMC_EXT_DEQUE_ITER */
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_deque_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_deque_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_deque_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _push_front)(struct SNAME *_deque_, V value);
|
||||
bool CMC_(PFX, _push_back)(struct SNAME *_deque_, V value);
|
||||
bool CMC_(PFX, _pop_front)(struct SNAME *_deque_);
|
||||
bool CMC_(PFX, _pop_back)(struct SNAME *_deque_);
|
||||
/* Element Access */
|
||||
V CMC_(PFX, _front)(struct SNAME *_deque_);
|
||||
V CMC_(PFX, _back)(struct SNAME *_deque_);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_deque_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_deque_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_deque_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_deque_);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_deque_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_deque_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_deque_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_deque_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_deque1_, struct SNAME *_deque2_);
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Dynamic circular array of elements */
|
||||
V *buffer;
|
||||
/* Current circular array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of elements */
|
||||
size_t count;
|
||||
/* Index representing the front of the deque */
|
||||
size_t front;
|
||||
/* Index representing the back of the deque */
|
||||
size_t back;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Functions Table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
struct CMC_ALLOC_NODE_NAME *alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
@@ -0,0 +1,459 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Implementation Detail Functions */
|
||||
/* None */
|
||||
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _new_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (capacity < 1)
|
||||
return NULL;
|
||||
|
||||
if (!f_val)
|
||||
return NULL;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
struct SNAME *_list_ = alloc->malloc(sizeof(struct SNAME));
|
||||
|
||||
if (!_list_)
|
||||
return NULL;
|
||||
|
||||
_list_->buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_list_->buffer)
|
||||
{
|
||||
alloc->free(_list_);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_list_->capacity = capacity;
|
||||
_list_->count = 0;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
_list_->f_val = f_val;
|
||||
_list_->alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(_list_, callbacks);
|
||||
|
||||
return _list_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _clear)(struct SNAME *_list_)
|
||||
{
|
||||
if (_list_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
_list_->f_val->free(_list_->buffer[i]);
|
||||
}
|
||||
|
||||
memset(_list_->buffer, 0, sizeof(V) * _list_->capacity);
|
||||
|
||||
_list_->count = 0;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _free)(struct SNAME *_list_)
|
||||
{
|
||||
if (_list_->f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
_list_->f_val->free(_list_->buffer[i]);
|
||||
}
|
||||
|
||||
_list_->alloc->free(_list_->buffer);
|
||||
_list_->alloc->free(_list_);
|
||||
}
|
||||
|
||||
void CMC_(PFX, _customize)(struct SNAME *_list_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
if (!alloc)
|
||||
_list_->alloc = &cmc_alloc_node_default;
|
||||
else
|
||||
_list_->alloc = alloc;
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(_list_, callbacks);
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_front)(struct SNAME *_list_, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_list_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_list_, _list_->count * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
memmove(_list_->buffer + 1, _list_->buffer, _list_->count * sizeof(V));
|
||||
}
|
||||
|
||||
_list_->buffer[0] = value;
|
||||
|
||||
_list_->count++;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_at)(struct SNAME *_list_, V value, size_t index)
|
||||
{
|
||||
if (index > _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CMC_(PFX, _full)(_list_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_list_, _list_->count * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(_list_->buffer + index + 1, _list_->buffer + index, (_list_->count - index) * sizeof(V));
|
||||
|
||||
_list_->buffer[index] = value;
|
||||
_list_->count++;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _push_back)(struct SNAME *_list_, V value)
|
||||
{
|
||||
if (CMC_(PFX, _full)(_list_))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_list_, _list_->count * 2))
|
||||
return false;
|
||||
}
|
||||
|
||||
_list_->buffer[_list_->count++] = value;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_front)(struct SNAME *_list_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(_list_->buffer, _list_->buffer + 1, (_list_->count - 1) * sizeof(V));
|
||||
|
||||
_list_->buffer[--_list_->count] = (V){ 0 };
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_at)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(_list_->buffer + index, _list_->buffer + index + 1, (_list_->count - index - 1) * sizeof(V));
|
||||
|
||||
_list_->buffer[--_list_->count] = (V){ 0 };
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _pop_back)(struct SNAME *_list_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
return false;
|
||||
|
||||
_list_->buffer[--_list_->count] = (V){ 0 };
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _front)(struct SNAME *_list_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, read);
|
||||
|
||||
return _list_->buffer[0];
|
||||
}
|
||||
|
||||
V CMC_(PFX, _get)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, read);
|
||||
|
||||
return _list_->buffer[index];
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_list_, size_t index)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (index >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, read);
|
||||
|
||||
return &(_list_->buffer[index]);
|
||||
}
|
||||
|
||||
V CMC_(PFX, _back)(struct SNAME *_list_)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(_list_))
|
||||
{
|
||||
_list_->flag = CMC_FLAG_EMPTY;
|
||||
return (V){ 0 };
|
||||
}
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, read);
|
||||
|
||||
return _list_->buffer[_list_->count - 1];
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _index_of)(struct SNAME *_list_, V value, bool from_start)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
size_t result = _list_->count;
|
||||
|
||||
if (from_start)
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
{
|
||||
if (_list_->f_val->cmp(_list_->buffer[i], value) == 0)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = _list_->count; i > 0; i--)
|
||||
{
|
||||
if (_list_->f_val->cmp(_list_->buffer[i - 1], value) == 0)
|
||||
{
|
||||
result = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_list_, V value)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
{
|
||||
if (_list_->f_val->cmp(_list_->buffer[i], value) == 0)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, read);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_list_)
|
||||
{
|
||||
return _list_->count == 0;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _full)(struct SNAME *_list_)
|
||||
{
|
||||
return _list_->count >= _list_->capacity;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_list_)
|
||||
{
|
||||
return _list_->count;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _fits)(struct SNAME *_list_, size_t size)
|
||||
{
|
||||
return _list_->count + size <= _list_->capacity;
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_list_)
|
||||
{
|
||||
return _list_->capacity;
|
||||
}
|
||||
|
||||
int CMC_(PFX, _flag)(struct SNAME *_list_)
|
||||
{
|
||||
return _list_->flag;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_list_, size_t capacity)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_list_->capacity == capacity)
|
||||
return true;
|
||||
|
||||
if (capacity < _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
V *new_buffer = _list_->alloc->realloc(_list_->buffer, sizeof(V) * capacity);
|
||||
|
||||
if (!new_buffer)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_ALLOC;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO zero out new slots */
|
||||
|
||||
_list_->buffer = new_buffer;
|
||||
_list_->capacity = capacity;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, resize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_list_)
|
||||
{
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(_list_->capacity, _list_->f_val, _list_->alloc, NULL);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CMC_CALLBACKS_ASSIGN(result, _list_->callbacks);
|
||||
|
||||
if (_list_->f_val->cpy)
|
||||
{
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
result->buffer[i] = _list_->f_val->cpy(_list_->buffer[i]);
|
||||
}
|
||||
else
|
||||
memcpy(result->buffer, _list_->buffer, sizeof(V) * _list_->count);
|
||||
|
||||
result->count = _list_->count;
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_list1_, struct SNAME *_list2_)
|
||||
{
|
||||
_list1_->flag = CMC_FLAG_OK;
|
||||
_list2_->flag = CMC_FLAG_OK;
|
||||
|
||||
if (_list1_->count != _list2_->count)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < _list1_->count; i++)
|
||||
{
|
||||
if (0 != _list1_->f_val->cmp(_list1_->buffer[i], _list2_->buffer[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val)
|
||||
{
|
||||
return CMC_(PFX, _init_custom)(capacity, f_val, NULL, NULL);
|
||||
}
|
||||
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks)
|
||||
{
|
||||
CMC_CALLBACKS_MAYBE_UNUSED(callbacks);
|
||||
|
||||
struct SNAME _list_ = { 0 };
|
||||
|
||||
if (capacity < 1)
|
||||
return _list_;
|
||||
|
||||
if (!f_val)
|
||||
return _list_;
|
||||
|
||||
if (!alloc)
|
||||
alloc = &cmc_alloc_node_default;
|
||||
|
||||
_list_.buffer = alloc->calloc(capacity, sizeof(V));
|
||||
|
||||
if (!_list_.buffer)
|
||||
return _list_;
|
||||
|
||||
_list_.capacity = capacity;
|
||||
_list_.count = 0;
|
||||
_list_.flag = CMC_FLAG_OK;
|
||||
_list_.f_val = f_val;
|
||||
_list_.alloc = alloc;
|
||||
CMC_CALLBACKS_ASSIGN(&_list_, callbacks);
|
||||
|
||||
return _list_;
|
||||
}
|
||||
|
||||
void CMC_(PFX, _release)(struct SNAME _list_)
|
||||
{
|
||||
if (_list_.f_val->free)
|
||||
{
|
||||
for (size_t i = 0; i < _list_.count; i++)
|
||||
_list_.f_val->free(_list_.buffer[i]);
|
||||
}
|
||||
|
||||
_list_.alloc->free(_list_.buffer);
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_LIST_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_ITER
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.start = true;
|
||||
iter.end = CMC_(PFX, _empty)(target);
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target)
|
||||
{
|
||||
struct CMC_DEF_ITER(SNAME) iter;
|
||||
|
||||
iter.target = target;
|
||||
iter.cursor = 0;
|
||||
iter.start = CMC_(PFX, _empty)(target);
|
||||
iter.end = true;
|
||||
|
||||
if (!CMC_(PFX, _empty)(target))
|
||||
iter.cursor = target->count - 1;
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->start;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return CMC_(PFX, _empty)(iter->target) || iter->end;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->cursor = 0;
|
||||
iter->start = true;
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (!CMC_(PFX, _empty)(iter->target))
|
||||
{
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
iter->cursor = iter->target->count - 1;
|
||||
iter->end = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->end)
|
||||
return false;
|
||||
|
||||
if (iter->cursor + 1 == iter->target->count)
|
||||
{
|
||||
iter->end = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->cursor + steps >= iter->target->count)
|
||||
return false;
|
||||
|
||||
iter->start = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor += steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator moved */
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps)
|
||||
{
|
||||
if (iter->start)
|
||||
return false;
|
||||
|
||||
if (iter->cursor == 0)
|
||||
{
|
||||
iter->start = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (steps == 0 || iter->cursor < steps)
|
||||
return false;
|
||||
|
||||
iter->end = CMC_(PFX, _empty)(iter->target);
|
||||
|
||||
iter->cursor -= steps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Returns true only if the iterator was able to be positioned at the */
|
||||
/* given index */
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index)
|
||||
{
|
||||
if (index >= iter->target->count)
|
||||
return false;
|
||||
|
||||
if (iter->cursor > index)
|
||||
return CMC_(PFX, _iter_rewind)(iter, iter->cursor - index);
|
||||
else if (iter->cursor < index)
|
||||
return CMC_(PFX, _iter_advance)(iter, index - iter->cursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return (V){ 0 };
|
||||
|
||||
return iter->target->buffer[iter->cursor];
|
||||
}
|
||||
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
if (CMC_(PFX, _empty)(iter->target))
|
||||
return NULL;
|
||||
|
||||
return &(iter->target->buffer[iter->cursor]);
|
||||
}
|
||||
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter)
|
||||
{
|
||||
return iter->cursor;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_LIST_ITER */
|
||||
|
||||
/**
|
||||
* SEQ
|
||||
*
|
||||
* Push and pop sequence of items.
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_SEQ
|
||||
|
||||
bool CMC_(PFX, _seq_push_front)(struct SNAME *_list_, V *values, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMC_(PFX, _fits)(_list_, size))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(_list_->buffer + size, _list_->buffer, _list_->count * sizeof(V));
|
||||
|
||||
memcpy(_list_->buffer, values, size * sizeof(V));
|
||||
|
||||
_list_->count += size;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _seq_push_at)(struct SNAME *_list_, V *values, size_t size, size_t index)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index > _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (index == 0)
|
||||
return CMC_(PFX, _seq_push_front)(_list_, values, size);
|
||||
else if (index == _list_->count)
|
||||
return CMC_(PFX, _seq_push_back)(_list_, values, size);
|
||||
|
||||
if (!CMC_(PFX, _fits)(_list_, size))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(_list_->buffer + index + size, _list_->buffer + index, (_list_->count - index) * sizeof(V));
|
||||
|
||||
memcpy(_list_->buffer + index, values, size * sizeof(V));
|
||||
|
||||
_list_->count += size;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _seq_push_back)(struct SNAME *_list_, V *values, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMC_(PFX, _fits)(_list_, size))
|
||||
{
|
||||
if (!CMC_(PFX, _resize)(_list_, _list_->count + size))
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(_list_->buffer + _list_->count, values, size * sizeof(V));
|
||||
|
||||
_list_->count += size;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, create);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _seq_pop_at)(struct SNAME *_list_, size_t from, size_t to)
|
||||
{
|
||||
if (from > to)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_INVALID;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (to >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t length = (to - from + 1);
|
||||
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(V));
|
||||
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V));
|
||||
|
||||
_list_->count -= to - from + 1;
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, delete);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SNAME *CMC_(PFX, _seq_sublist)(struct SNAME *_list_, size_t from, size_t to)
|
||||
{
|
||||
if (from > to)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_INVALID;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (to >= _list_->count)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_RANGE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t length = to - from + 1;
|
||||
|
||||
struct SNAME *result = CMC_(PFX, _new_custom)(length, _list_->f_val, _list_->alloc, CMC_CALLBACKS_GET(_list_));
|
||||
|
||||
if (!result)
|
||||
{
|
||||
_list_->flag = CMC_FLAG_ALLOC;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(result->buffer, _list_->buffer, length * sizeof(V));
|
||||
|
||||
memmove(_list_->buffer + from, _list_->buffer + to + 1, (_list_->count - to - 1) * sizeof(V));
|
||||
|
||||
memset(_list_->buffer + _list_->count - length, 0, length * sizeof(V));
|
||||
|
||||
_list_->count -= length;
|
||||
result->count = length;
|
||||
|
||||
_list_->flag = CMC_FLAG_OK;
|
||||
|
||||
CMC_CALLBACKS_CALL(_list_, delete);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_LIST_SEQ */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_STR
|
||||
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_list_, FILE *fptr)
|
||||
{
|
||||
struct SNAME *l_ = _list_;
|
||||
|
||||
return 0 <= fprintf(fptr,
|
||||
"struct %s<%s> "
|
||||
"at %p { "
|
||||
"buffer:%p, "
|
||||
"capacity:%" PRIuMAX ", "
|
||||
"count:%" PRIuMAX ", "
|
||||
"flag:%d, "
|
||||
"f_val:%p, "
|
||||
"alloc:%p, "
|
||||
"callbacks:%p }",
|
||||
CMC_TO_STRING(SNAME), CMC_TO_STRING(V), l_, l_->buffer, l_->capacity, l_->count, l_->flag,
|
||||
l_->f_val, l_->alloc, CMC_CALLBACKS_GET(l_));
|
||||
}
|
||||
|
||||
bool CMC_(PFX, _print)(struct SNAME *_list_, FILE *fptr, const char *start, const char *separator, const char *end)
|
||||
{
|
||||
fprintf(fptr, "%s", start);
|
||||
|
||||
for (size_t i = 0; i < _list_->count; i++)
|
||||
{
|
||||
if (!_list_->f_val->str(fptr, _list_->buffer[i]))
|
||||
return false;
|
||||
|
||||
if (i + 1 < _list_->count)
|
||||
fprintf(fptr, "%s", separator);
|
||||
}
|
||||
|
||||
fprintf(fptr, "%s", end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* CMC_EXT_LIST_STR */
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT
|
||||
*
|
||||
* The part 'INIT' gives a new way of initializing a collection. The collection
|
||||
* struct is not heap allocated, only its internal structure (nodes, buffers).
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_INIT
|
||||
|
||||
struct SNAME CMC_(PFX, _init)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME CMC_(PFX, _init_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _release)(struct SNAME _list_);
|
||||
|
||||
#endif /* CMC_EXT_LIST_INIT */
|
||||
|
||||
/**
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_ITER
|
||||
|
||||
/* Iterator Initialization */
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_start)(struct SNAME *target);
|
||||
struct CMC_DEF_ITER(SNAME) CMC_(PFX, _iter_end)(struct SNAME *target);
|
||||
/* Iterator State */
|
||||
bool CMC_(PFX, _iter_at_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_at_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
/* Iterator Movement */
|
||||
bool CMC_(PFX, _iter_to_start)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_to_end)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_next)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_prev)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
bool CMC_(PFX, _iter_advance)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_rewind)(struct CMC_DEF_ITER(SNAME) * iter, size_t steps);
|
||||
bool CMC_(PFX, _iter_go_to)(struct CMC_DEF_ITER(SNAME) * iter, size_t index);
|
||||
/* Iterator Access */
|
||||
V CMC_(PFX, _iter_value)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
V *CMC_(PFX, _iter_rvalue)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
size_t CMC_(PFX, _iter_index)(struct CMC_DEF_ITER(SNAME) * iter);
|
||||
|
||||
#endif /* CMC_EXT_LIST_ITER */
|
||||
|
||||
/**
|
||||
* SEQ
|
||||
*
|
||||
* Push and pop sequence of items.
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_SEQ
|
||||
|
||||
/* List Sequence Input and Output */
|
||||
bool CMC_(PFX, _seq_push_front)(struct SNAME *_list_, V *values, size_t size);
|
||||
bool CMC_(PFX, _seq_push_at)(struct SNAME *_list_, V *values, size_t size, size_t index);
|
||||
bool CMC_(PFX, _seq_push_back)(struct SNAME *_list_, V *values, size_t size);
|
||||
bool CMC_(PFX, _seq_pop_at)(struct SNAME *_list_, size_t from, size_t to);
|
||||
struct SNAME *CMC_(PFX, _seq_sublist)(struct SNAME *_list_, size_t from, size_t to);
|
||||
|
||||
#endif /* CMC_EXT_LIST_SEQ */
|
||||
|
||||
/**
|
||||
* STR
|
||||
*
|
||||
* Print helper functions.
|
||||
*/
|
||||
#ifdef CMC_EXT_LIST_STR
|
||||
|
||||
/* Debug prints the struct to fptr */
|
||||
bool CMC_(PFX, _to_string)(struct SNAME *_list_, FILE *fptr);
|
||||
/* Prints each item in the list as an array */
|
||||
bool CMC_(PFX, _print)(struct SNAME *_list_, FILE *fptr, const char *start, const char *separator, const char *end);
|
||||
|
||||
#endif /* CMC_EXT_LIST_STR */
|
||||
@@ -23,34 +23,26 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* ext_cmc_bitset.h
|
||||
*
|
||||
* Creation Date: 08/06/2020
|
||||
*
|
||||
* Authors:
|
||||
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||
* ITER
|
||||
*
|
||||
* List bi-directional iterator.
|
||||
*/
|
||||
#ifdef CMC_EXT_DEQUE_ITER
|
||||
|
||||
#ifndef CMC_EXT_CMC_BITSET_H
|
||||
#define CMC_EXT_CMC_BITSET_H
|
||||
/* List Iterator */
|
||||
struct CMC_DEF_ITER(SNAME)
|
||||
{
|
||||
/* Target List */
|
||||
struct SNAME *target;
|
||||
|
||||
#include "cor_core.h"
|
||||
/* Cursor's position (index) */
|
||||
size_t cursor;
|
||||
|
||||
/**
|
||||
* All the EXT parts of CMC BitSet.
|
||||
*/
|
||||
#define CMC_EXT_CMC_BITSET_PARTS PLACEHOLDER
|
||||
/* If the iterator has reached the start of the iteration */
|
||||
bool start;
|
||||
|
||||
#define CMC_EXT_CMC_BITSET_PLACEHOLDER(ACCESS, FILE, PARAMS) \
|
||||
CMC_(CMC_(CMC_EXT_CMC_BITSET_PLACEHOLDER_, ACCESS), CMC_(_, FILE))(PARAMS)
|
||||
/* If the iterator has reached the end of the iteration */
|
||||
bool end;
|
||||
};
|
||||
|
||||
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PUBLIC_HEADER(PARAMS)
|
||||
|
||||
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PUBLIC_SOURCE(PARAMS)
|
||||
|
||||
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PRIVATE_HEADER(PARAMS)
|
||||
|
||||
#define CMC_EXT_CMC_BITSET_PLACEHOLDER_PRIVATE_SOURCE(PARAMS)
|
||||
|
||||
#endif /* CMC_EXT_CMC_BITSET_H */
|
||||
#endif /* CMC_EXT_DEQUE_ITER */
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Collection Allocation and Deallocation */
|
||||
struct SNAME *CMC_(PFX, _new)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val);
|
||||
struct SNAME *CMC_(PFX, _new_custom)(size_t capacity, struct CMC_DEF_FVAL(SNAME) * f_val,
|
||||
struct CMC_ALLOC_NODE_NAME *alloc, struct CMC_CALLBACKS_NAME *callbacks);
|
||||
void CMC_(PFX, _clear)(struct SNAME *_list_);
|
||||
void CMC_(PFX, _free)(struct SNAME *_list_);
|
||||
/* Customization of Allocation and Callbacks */
|
||||
void CMC_(PFX, _customize)(struct SNAME *_list_, struct CMC_ALLOC_NODE_NAME *alloc,
|
||||
struct CMC_CALLBACKS_NAME *callbacks);
|
||||
/* Collection Input and Output */
|
||||
bool CMC_(PFX, _push_front)(struct SNAME *_list_, V value);
|
||||
bool CMC_(PFX, _push_at)(struct SNAME *_list_, V value, size_t index);
|
||||
bool CMC_(PFX, _push_back)(struct SNAME *_list_, V value);
|
||||
bool CMC_(PFX, _pop_front)(struct SNAME *_list_);
|
||||
bool CMC_(PFX, _pop_at)(struct SNAME *_list_, size_t index);
|
||||
bool CMC_(PFX, _pop_back)(struct SNAME *_list_);
|
||||
/* Element Access */
|
||||
V CMC_(PFX, _front)(struct SNAME *_list_);
|
||||
V CMC_(PFX, _get)(struct SNAME *_list_, size_t index);
|
||||
V *CMC_(PFX, _get_ref)(struct SNAME *_list_, size_t index);
|
||||
V CMC_(PFX, _back)(struct SNAME *_list_);
|
||||
size_t CMC_(PFX, _index_of)(struct SNAME *_list_, V value, bool from_start);
|
||||
/* Collection State */
|
||||
bool CMC_(PFX, _contains)(struct SNAME *_list_, V value);
|
||||
bool CMC_(PFX, _empty)(struct SNAME *_list_);
|
||||
bool CMC_(PFX, _full)(struct SNAME *_list_);
|
||||
size_t CMC_(PFX, _count)(struct SNAME *_list_);
|
||||
bool CMC_(PFX, _fits)(struct SNAME *_list_, size_t size);
|
||||
size_t CMC_(PFX, _capacity)(struct SNAME *_list_);
|
||||
int CMC_(PFX, _flag)(struct SNAME *_list_);
|
||||
/* Collection Utility */
|
||||
bool CMC_(PFX, _resize)(struct SNAME *_list_, size_t capacity);
|
||||
struct SNAME *CMC_(PFX, _copy_of)(struct SNAME *_list_);
|
||||
bool CMC_(PFX, _equals)(struct SNAME *_list1_, struct SNAME *_list2_);
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2019 Leonardo Vencovsky
|
||||
*
|
||||
* This file is part of the C Macro Collections Libray.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
struct SNAME
|
||||
{
|
||||
/* Dynamic array of elements */
|
||||
V *buffer;
|
||||
/* Current array capacity */
|
||||
size_t capacity;
|
||||
/* Current amount of elements */
|
||||
size_t count;
|
||||
/* Flags indicating errors or success */
|
||||
int flag;
|
||||
/* Value function table */
|
||||
struct CMC_DEF_FVAL(SNAME) * f_val;
|
||||
/* Custom allocation functions */
|
||||
struct CMC_ALLOC_NODE_NAME *alloc;
|
||||
/* Custom callback functions */
|
||||
CMC_CALLBACKS_DECL;
|
||||
};
|
||||
|
||||
struct CMC_DEF_FVAL(SNAME)
|
||||
{
|
||||
/* Comparator function */
|
||||
CMC_DEF_FTAB_CMP(V);
|
||||
/* Copy function */
|
||||
CMC_DEF_FTAB_CPY(V);
|
||||
/* To string function */
|
||||
CMC_DEF_FTAB_STR(V);
|
||||
/* Free from memory function */
|
||||
CMC_DEF_FTAB_FREE(V);
|
||||
/* Hash function */
|
||||
CMC_DEF_FTAB_HASH(V);
|
||||
/* Priority function */
|
||||
CMC_DEF_FTAB_PRI(V);
|
||||
};
|
||||
Loaded 100 of 213 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user