Merge remote-tracking branch 'refs/remotes/origin/main'

v1
Brett 2024-10-01 14:41:01 -04:00
commit bfcb357059
24 changed files with 1194 additions and 733 deletions

View File

@ -1,4 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CMakePythonSetting">
<option name="pythonIntegrationState" value="YES" />
</component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" /> <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project> </project>

32
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,32 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/cmake-build-debug/BLT_TESTS",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
]
}
]
}

75
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,75 @@
{
"files.associations": {
"iostream": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"strstream": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"chrono": "cpp",
"cinttypes": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"scoped_allocator": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cfenv": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"variant": "cpp"
}
}

View File

@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake) include(cmake/color.cmake)
set(BLT_VERSION 0.21.3) set(BLT_VERSION 1.1.7)
set(BLT_TEST_VERSION 0.0.1)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)
@ -34,6 +33,8 @@ if(${BLT_DISABLE_STATS})
add_compile_definitions(BLT_DISABLE_STATS) add_compile_definitions(BLT_DISABLE_STATS)
endif () endif ()
find_program(MOLD "mold")
configure_file(include/blt/config.h.in config/blt/config.h @ONLY) configure_file(include/blt/config.h.in config/blt/config.h @ONLY)
message("Enabling library compilation") message("Enabling library compilation")
@ -138,28 +139,62 @@ install(FILES ${CMAKE_BINARY_DIR}/config/blt/config.h DESTINATION ${CMAKE_INSTAL
set_target_properties(${BLT_TARGET} PROPERTIES VERSION ${BLT_VERSION}) set_target_properties(${BLT_TARGET} PROPERTIES VERSION ${BLT_VERSION})
set_target_properties(${BLT_TARGET} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) set_target_properties(${BLT_TARGET} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR})
if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND)
target_link_options(${BLT_TARGET} PUBLIC -fuse-ld=mold)
endif ()
install(TARGETS ${BLT_TARGET} install(TARGETS ${BLT_TARGET}
CONFIGURATIONS RelWithDebInfo CONFIGURATIONS RelWithDebInfo
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
macro(blt_add_project name source type)
project(${name}-${type})
add_executable(${name}-${type} ${source})
if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND)
add_link_options(-fuse-ld=mold)
endif ()
target_link_libraries(${name}-${type} PRIVATE BLT)
target_compile_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
target_link_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
target_compile_definitions(${name}-${type} PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL})
if (${TRACK_ALLOCATIONS})
target_compile_definitions(${name}-${type} PRIVATE BLT_TRACK_ALLOCATIONS=1)
endif ()
if (${ENABLE_ADDRSAN} MATCHES ON)
target_compile_options(${name}-${type} PRIVATE -fsanitize=address)
target_link_options(${name}-${type} PRIVATE -fsanitize=address)
endif ()
if (${ENABLE_UBSAN} MATCHES ON)
target_compile_options(${name}-${type} PRIVATE -fsanitize=undefined)
target_link_options(${name}-${type} PRIVATE -fsanitize=undefined)
endif ()
if (${ENABLE_TSAN} MATCHES ON)
target_compile_options(${name}-${type} PRIVATE -fsanitize=thread)
target_link_options(${name}-${type} PRIVATE -fsanitize=thread)
endif ()
add_test(NAME ${name} COMMAND ${name}-${type})
set(failRegex "\\[WARN\\]" "FAIL" "ERROR" "FATAL" "exception")
set_property(TEST ${name} PROPERTY FAIL_REGULAR_EXPRESSION "${failRegex}")
project(${BLT_TARGET})
endmacro()
if (${BUILD_TESTS}) if (${BUILD_TESTS})
message("Building test version ${BLT_TEST_VERSION}") message("Building tests for version ${BLT_VERSION}")
project(BLT_TESTS VERSION ${BLT_TEST_VERSION})
include_directories(tests/include) blt_add_project(blt-iterator tests/iterator_tests.cpp test)
file(GLOB_RECURSE TEST_FILES "${CMAKE_CURRENT_SOURCE_DIR}/tests/src/*.cpp")
message("Using files ${TEST_FILES}")
add_executable(BLT_TESTS ${TEST_FILES})
target_link_libraries(BLT_TESTS PRIVATE BLT)
include(cmake/warnings.cmake)
include(cmake/sanitizers.cmake)
message("Built tests") message("Built tests")
endif () endif ()

260
commit.py
View File

@ -1,6 +1,13 @@
#!/usr/bin/python3 #!/usr/bin/python3
import subprocess import subprocess
import argparse
import sys
import os
import itertools
import requests
import json
from pathlib import Path
#--------------------------------------- #---------------------------------------
# CONFIG # CONFIG
@ -8,12 +15,110 @@ import subprocess
VERSION_BEGIN_STR = "set(BLT_VERSION " VERSION_BEGIN_STR = "set(BLT_VERSION "
VERSION_END_STR = ")" VERSION_END_STR = ")"
PATCH_LIMIT = 1000
#--------------------------------------- #---------------------------------------
# DO NOT TOUCH # DO NOT TOUCH
#--------------------------------------- #---------------------------------------
USER_HOME = Path.home()
ENVIRONMENT_DATA_LOCATION = USER_HOME / ".brett_scripts.env"
if sys.platform.startswith("win"):
CONFIG_FILE_DIRECTORY = Path(os.getenv('APPDATA') + "\blt")
CONFIG_FILE_LOCATION = Path(CONFIG_FILE_DIRECTORY + "\commit_config.json")
else:
XDG_CONFIG_HOME = os.environ.get('XDG_CONFIG_HOME')
if XDG_CONFIG_HOME is None:
XDG_CONFIG_HOME = USER_HOME / ".config"
else:
XDG_CONFIG_HOME = Path(XDG_CONFIG_HOME)
if len(str(XDG_CONFIG_HOME)) == 0:
XDG_CONFIG_HOME = USER_HOME
CONFIG_FILE_DIRECTORY = XDG_CONFIG_HOME / "blt"
CONFIG_FILE_LOCATION = CONFIG_FILE_DIRECTORY / "commit_config.json"
class Config:
def __init__(self):
# Inline with semantic versioning it doesn't make sense to branch / release on minor
self.branch_on_major = True
self.branch_on_minor = False
self.release_on_major = True
self.release_on_minor = True
self.main_branch = "main"
self.patch_limit = -1
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
def fromJSON(file):
with open(file, "r") as f:
j = json.load(f)
obj = Config()
[setattr(obj, key, val) for key, val in j.items() if hasattr(obj, key)]
if obj.branch_on_minor:
obj.branch_on_major = True
return obj
def from_file(file):
values = {}
if (not os.path.exists(file)):
return Config()
with open(file, "r") as f:
j = json.load(f)
obj = Config()
[setattr(obj, key, val) for key, val in j.items() if hasattr(obj, key)]
return obj
def save_to_file(self, file):
dir_index = str(file).rfind("/")
dir = str(file)[:dir_index]
if not os.path.exists(dir):
print(f"Creating config directory {dir}")
os.makedirs(dir)
with open(file, "w") as f:
json.dump(self, f, default=lambda o: o.__dict__, sort_keys=True, indent=4)
class EnvData:
def __init__(self, github_username = '', github_token = ''):
self.github_token = github_token
self.github_username = github_username
def get_env_from_file(file):
f = open(file, "rt")
values = {}
for line in f:
if line.startswith("export"):
content = line.split("=")
for idx, c in enumerate(content):
content[idx] = c.replace("export", "").strip()
values[content[0]] = content[1].replace("\"", "").replace("'", "")
try:
github_token = values["github_token"]
except Exception:
print("Failed to parse github token!")
try:
github_username = values["github_username"]
except:
print("Failed to parse github username! Assuming you are me!")
github_username = "Tri11Paragon"
return EnvData(github_username=github_username, github_token=github_token)
def open_process(command, print_out = True):
process = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = process.communicate()
exit_code = process.wait()
str_out = stdout.decode('utf8')
str_err = stderr.decode('utf8')
if print_out and len(str_out) > 0:
print(str_out, end='')
if print_out and len(str_err) > 0:
print(str_err, end='')
#print(stdout, stderr, exit_code)
return (stdout, stderr, exit_code)
def load_cmake(): def load_cmake():
cmake_file = open("CMakeLists.txt", 'r') cmake_file = open("CMakeLists.txt", 'r')
cmake_text = cmake_file.read() cmake_text = cmake_file.read()
@ -38,9 +143,8 @@ def split_version(cmake_text):
def recombine(cmake_text, version_parts, begin, end): def recombine(cmake_text, version_parts, begin, end):
constructed_version = version_parts[0] + '.' + version_parts[1] + '.' + version_parts[2] constructed_version = version_parts[0] + '.' + version_parts[1] + '.' + version_parts[2]
constructed_text_begin = cmake_text[0:begin] constructed_text_begin = cmake_text[0:begin]
constrcuted_text_end = cmake_text[end::] constructed_text_end = cmake_text[end::]
return constructed_text_begin + constructed_version + constrcuted_text_end return constructed_text_begin + constructed_version + constructed_text_end
def inc_major(cmake_text): def inc_major(cmake_text):
version_parts, begin, end = split_version(cmake_text) version_parts, begin, end = split_version(cmake_text)
@ -55,32 +159,158 @@ def inc_minor(cmake_text):
version_parts[2] = '0' version_parts[2] = '0'
return recombine(cmake_text, version_parts, begin, end) return recombine(cmake_text, version_parts, begin, end)
def inc_patch(cmake_text): def inc_patch(config: Config, cmake_text):
version_parts, begin, end = split_version(cmake_text) version_parts, begin, end = split_version(cmake_text)
if int(version_parts[2]) + 1 >= PATCH_LIMIT: if config.patch_limit > 0 and int(version_parts[2]) + 1 >= config.patch_limit:
return inc_minor(cmake_text) return inc_minor(cmake_text)
version_parts[2] = str(int(version_parts[2]) + 1) version_parts[2] = str(int(version_parts[2]) + 1)
return recombine(cmake_text, version_parts, begin, end) return recombine(cmake_text, version_parts, begin, end)
cmake_text = load_cmake() def make_branch(config: Config, name):
cmake_version = get_version(cmake_text)[0] print(f"Making new branch {name}")
print(f"Current Version: {cmake_version}") subprocess.call(["git", "checkout", "-b", name])
subprocess.call(["git", "merge", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
try: def sync_branch(config: Config, version_parts, args):
if config.branch_on_major:
# Branch will be created.
if args.minor:
return;
def make_release(env: EnvData, name):
print(f"Making new release {name}")
repos_v = open_process(["git", "remote", "-v"])[0].splitlines()
urls = []
for line in repos_v:
origin = ''.join(itertools.takewhile(str.isalpha, line.decode('utf8')))
urls.append(open_process(["git", "remote", "get-url", origin], False)[0].decode('utf8').replace("\n", "").replace(".git", "").replace("https://github.com/", "https://api.github.com/repos/") + "/releases")
urls = set(urls)
data = {
'tag_name': name,
'name': name,
'body': "Automated Release '" + name + "'",
'draft': False,
'prerelease': False
}
headers = {
'Authorization': f'Bearer {env.github_token}',
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28'
}
for url in urls:
response = requests.post(url, headers=headers, data=json.dumps(data))
if response.status_code == 201:
print('Release created successfully!')
release_data = response.json()
print(f"Release URL: {release_data['html_url']}")
else:
print(f"Failed to create release: {response.status_code}")
print(response.json())
def main():
parser = argparse.ArgumentParser(
prog="Commit Helper",
description="Help you make pretty commits :3")
parser.add_argument("action", nargs='?', default=None)
parser.add_argument("-p", "--patch", action='store_true', default=False, required=False)
parser.add_argument("-m", "--minor", action='store_true', default=False, required=False)
parser.add_argument("-M", "--major", action='store_true', default=False, required=False)
parser.add_argument('-e', "--env", help="environment file", required=False, default=None)
parser.add_argument('-c', "--config", help="config file", required=False, default=None)
parser.add_argument("--create-default-config", action="store_true", default=False, required=False)
parser.add_argument("--no-release", action="store_true", default=False, required=False)
parser.add_argument("--no-branch", action="store_true", default=False, required=False)
args = parser.parse_args()
if args.create_default_config:
config = Config()
config.save_to_file(args.config if args.config is not None else CONFIG_FILE_LOCATION)
return
if args.env is not None:
env = EnvData.get_env_from_file(args.e)
else:
env = EnvData.get_env_from_file(ENVIRONMENT_DATA_LOCATION)
if args.config is not None:
config = Config.from_file(args.config)
else:
config = Config.from_file(CONFIG_FILE_LOCATION)
cmake_text = load_cmake()
cmake_version = get_version(cmake_text)[0]
print(f"Current Version: {cmake_version}")
if not (args.patch or args.minor or args.major):
try:
if args.action is not None:
type = args.action
else:
type = input("What kind of commit is this ((M)ajor, (m)inor, (p)atch)? ") type = input("What kind of commit is this ((M)ajor, (m)inor, (p)atch)? ")
if type.startswith('M'): if type.startswith('M'):
args.major = True
elif type.startswith('m'):
args.minor = True
elif type.startswith('p') or type.startswith('P') or len(type) == 0:
args.patch = True
except KeyboardInterrupt:
print("\nCancelling!")
return
if args.major:
print("Selected major") print("Selected major")
write_cmake(inc_major(cmake_text)) write_cmake(inc_major(cmake_text))
elif type.startswith('m'): elif args.minor:
print("Selected minor") print("Selected minor")
write_cmake(inc_minor(cmake_text)) write_cmake(inc_minor(cmake_text))
elif type.startswith('p') or type.startswith('P') or len(type) == 0: elif args.patch:
print("Selected patch") print("Selected patch")
write_cmake(inc_patch(cmake_text)) write_cmake(inc_patch(config, cmake_text))
subprocess.call(["git", "add", "*"]) subprocess.call(["git", "add", "*"])
subprocess.call(["git", "commit"]) subprocess.call(["git", "commit"])
cmake_text = load_cmake()
version_parts = split_version(cmake_text)[0]
if args.major:
if config.branch_on_major:
if not args.no_branch:
make_branch(config, "v" + str(version_parts[0]))
if args.minor:
if config.branch_on_minor:
if not args.no_branch:
make_branch(config, "v" + str(version_parts[0]) + "." + str(version_parts[1]))
elif config.branch_on_major:
subprocess.call(["git", "checkout", "v" + str(version_parts[0])])
subprocess.call(["git", "rebase", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
if args.patch:
if config.branch_on_minor:
subprocess.call(["git", "checkout", "v" + str(version_parts[0]) + "." + str(version_parts[1])])
subprocess.call(["git", "rebase", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
elif config.branch_on_major:
subprocess.call(["git", "checkout", "v" + str(version_parts[0])])
subprocess.call(["git", "rebase", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
sync_branch(config=config, version_parts=version_parts, args=args)
subprocess.call(["sh", "-c", "git remote | xargs -L1 git push --all"]) subprocess.call(["sh", "-c", "git remote | xargs -L1 git push --all"])
except KeyboardInterrupt:
print("\nCancelling!") if args.major:
if not args.no_release and config.release_on_major:
make_release(env, "v" + str(version_parts[0]))
if args.minor:
if not args.no_release and config.release_on_minor:
make_release(env, "v" + str(version_parts[0]) + "." + str(version_parts[1]))
if __name__ == "__main__":
main()

View File

@ -0,0 +1,271 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_ITERATOR_ITER_COMMON
#define BLT_ITERATOR_ITER_COMMON
#include <type_traits>
#include <iterator>
#include <blt/meta/meta.h>
namespace blt::iterator
{
template<typename Derived>
struct base_wrapper
{
base_wrapper operator++(int)
{
auto tmp = *this;
++*this;
return tmp;
}
base_wrapper operator--(int)
{
static_assert(std::is_same_v<typename Derived::iterator_category, std::bidirectional_iterator_tag> ||
std::is_same_v<typename Derived::iterator_category,
std::random_access_iterator_tag>,
"Iterator must allow random access");
auto tmp = *this;
--*this;
return tmp;
}
auto operator[](blt::ptrdiff_t n) const
{
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
"Iterator must allow random access");
return *(*this + n);
}
friend base_wrapper operator+(blt::ptrdiff_t n, const base_wrapper& a)
{
return a + n;
}
friend bool operator<(const base_wrapper& a, const base_wrapper& b)
{
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
"Iterator must allow random access");
return b - a > 0;
}
friend bool operator>(const base_wrapper& a, const base_wrapper& b)
{
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
"Iterator must allow random access");
return b < a;
}
friend bool operator>=(const base_wrapper& a, base_wrapper& b)
{
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
"Iterator must allow random access");
return !(a < b); // NOLINT
}
friend bool operator<=(const base_wrapper& a, const base_wrapper& b)
{
static_assert(std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>,
"Iterator must allow random access");
return !(a > b); // NOLINT
}
friend bool operator==(const base_wrapper& a, const base_wrapper& b)
{
return static_cast<const Derived&>(a).base() == static_cast<const Derived&>(b).base();
}
friend bool operator!=(const base_wrapper& a, const base_wrapper& b)
{
return !(static_cast<const Derived&>(a).base() == static_cast<const Derived&>(b).base()); // NOLINT
}
};
template<typename Iter, typename Derived, bool dereference = false>
struct passthrough_wrapper : public base_wrapper<Derived>
{
public:
explicit passthrough_wrapper(Iter iter): iter(std::move(iter))
{}
auto base() const
{
return iter;
}
friend blt::ptrdiff_t operator-(const passthrough_wrapper& a, const passthrough_wrapper& b)
{
return a.base() - b.base();
}
protected:
Iter iter;
};
template<typename Iter, typename Derived>
struct passthrough_wrapper<Iter, Derived, true> : public passthrough_wrapper<Iter, Derived>
{
using passthrough_wrapper<Iter, Derived>::passthrough_wrapper;
meta::deref_return_t<Iter> operator*() const
{
return *this->iter;
}
};
namespace impl
{
template<typename Derived>
class skip_t
{
private:
template<bool check>
auto skip_base(blt::size_t n)
{
auto* d = static_cast<Derived*>(this);
auto begin = d->begin();
auto end = d->end();
if constexpr (std::is_same_v<typename Derived::iterator_category, std::forward_iterator_tag> ||
std::is_same_v<typename Derived::iterator_category, std::bidirectional_iterator_tag>)
{
for (blt::size_t i = 0; i < n; i++)
{
if constexpr (check)
{
if (begin == end)
break;
}
++begin;
}
return Derived{std::move(begin), std::move(end)};
} else if constexpr (std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>)
{
// random access iterators can have math directly applied to them.
if constexpr (check)
{
return Derived{begin + std::min(static_cast<blt::ptrdiff_t>(n), std::distance(begin, end)), end};
} else
{
return Derived{begin + n, end};
}
}
}
public:
auto skip(blt::size_t n)
{ return skip_base<false>(n); }
auto skip_or(blt::size_t n)
{ return skip_base<true>(n); }
};
template<typename Derived>
class take_t
{
private:
template<bool check>
auto take_base(blt::size_t n)
{
static_assert(!std::is_same_v<typename Derived::iterator_category, std::input_iterator_tag>,
"Cannot .take() on an input iterator!");
auto* d = static_cast<Derived*>(this);
auto begin = d->begin();
auto end = d->end();
// take variant for forward and bidirectional iterators
if constexpr (std::is_same_v<typename Derived::iterator_category, std::forward_iterator_tag> ||
std::is_same_v<typename Derived::iterator_category, std::bidirectional_iterator_tag>)
{
// with these guys we have to loop forward to move the iterators. an unfortunate inefficiency
auto new_end = begin;
for (blt::size_t i = 0; i < n; i++)
{
if constexpr (check)
{
if (new_end == end)
break;
}
++new_end;
}
return Derived{std::move(begin), std::move(new_end)};
} else if constexpr (std::is_same_v<typename Derived::iterator_category, std::random_access_iterator_tag>)
{
// random access iterators can have math directly applied to them.
if constexpr (check)
{
return Derived{begin, begin + std::min(static_cast<blt::ptrdiff_t>(n), std::distance(begin, end))};
} else
{
return Derived{begin, begin + n};
}
}
}
public:
auto take(blt::size_t n)
{ return take_base<false>(n); }
auto take_or(blt::size_t n)
{ return take_base<true>(n); }
};
}
template<typename IterBase>
class iterator_container : public impl::take_t<iterator_container<IterBase>>,
public impl::skip_t<iterator_container<IterBase>>
{
public:
using iterator_category = typename IterBase::iterator_category;
using iterator = IterBase;
iterator_container(IterBase begin, IterBase end): m_begin(std::move(begin)), m_end(std::move(end))
{}
template<typename Iter>
iterator_container(Iter&& begin, Iter&& end): m_begin(std::forward<Iter>(begin)), m_end(std::forward<Iter>(end))
{}
auto rev()
{
static_assert((std::is_same_v<typename IterBase::iterator_category, std::bidirectional_iterator_tag> ||
std::is_same_v<typename IterBase::iterator_category, std::random_access_iterator_tag>),
".rev() must be used with bidirectional (or better) iterators!");
return iterator_container<std::reverse_iterator<IterBase>>{std::reverse_iterator<IterBase>{end()},
std::reverse_iterator<IterBase>{begin()}};
}
auto begin() const
{
return m_begin;
}
auto end() const
{
return m_end;
}
protected:
IterBase m_begin;
IterBase m_end;
};
}
#endif //BLT_ITERATOR_ITER_COMMON

View File

@ -0,0 +1,59 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_ITERATOR_ENUMERATE_H
#define BLT_ITERATOR_ENUMERATE_H
#include <blt/iterator/common.h>
#include <blt/meta/meta.h>
#include <tuple>
namespace blt
{
namespace iterator
{
/**
* struct which is returned by the enumerator.
* @tparam T type to store.
*/
template<typename T>
struct enumerate_item
{
blt::size_t index;
T value;
};
template<typename Iter>
class enumerate_wrapper : public passthrough_wrapper<Iter, enumerate_wrapper<Iter>>
{
public:
using passthrough_wrapper<Iter, enumerate_wrapper<Iter>>::passthrough_wrapper;
enumerate_item<meta::deref_return_t<Iter>> operator*() const
{
return *this->iter;
}
private:
blt::size_t index;
};
}
}
#endif //BLT_ITERATOR_ENUMERATE_H

View File

@ -21,7 +21,7 @@
#include <blt/std/types.h> #include <blt/std/types.h>
#include <blt/std/logging.h> #include <blt/std/logging.h>
#include <blt/iterator/iter_common.h> #include <blt/iterator/common.h>
#include <blt/iterator/zip.h> #include <blt/iterator/zip.h>
#include <blt/meta/meta.h> #include <blt/meta/meta.h>
#include <blt/meta/iterator.h> #include <blt/meta/iterator.h>
@ -59,118 +59,6 @@ namespace blt
template<typename Iter1, typename Iter2, typename = std::void_t<>> template<typename Iter1, typename Iter2, typename = std::void_t<>>
class pair_wrapper; class pair_wrapper;
template<typename Tag, typename... Iter>
class zip_wrapper;
template<typename Tag, typename... Iter>
class zip_iterator_storage;
template<typename Tag, typename... Iter>
class zip_iterator_storage_rev;
template<typename... Iter>
class zip_forward_iterator
{
public:
explicit zip_forward_iterator(Iter... iter): iter(std::make_tuple(iter...))
{}
std::tuple<blt::meta::deref_return_t<Iter>...> operator*() const
{
return std::apply([](auto& ... i) { return std::make_tuple(*i...); }, iter);
}
friend bool operator==(const zip_forward_iterator& a, const zip_forward_iterator& b)
{
return a.iter == b.iter;
}
friend bool operator!=(const zip_forward_iterator& a, const zip_forward_iterator& b)
{
return !(a.iter == b.iter);
}
zip_forward_iterator& operator++()
{
std::apply([](auto& ... i) { ((++i), ...); }, iter);
return *this;
}
zip_forward_iterator operator++(int)
{
auto tmp = *this;
++*this;
return tmp;
}
auto base()
{
return iter;
}
protected:
std::tuple<Iter...> iter;
};
template<typename... Iter>
class zip_bidirectional_iterator : public zip_forward_iterator<Iter...>
{
public:
using zip_forward_iterator<Iter...>::zip_forward_iterator;
zip_bidirectional_iterator& operator--()
{
std::apply([](auto& ... i) { ((--i), ...); }, this->iter);
return *this;
}
zip_bidirectional_iterator operator--(int)
{
auto tmp = *this;
--*this;
return tmp;
}
};
template<typename... Iter>
class zip_wrapper<std::forward_iterator_tag, Iter...> : public zip_forward_iterator<Iter...>
{
public:
using zip_forward_iterator<Iter...>::zip_forward_iterator;
using iterator_category = std::forward_iterator_tag;
using value_type = std::tuple<blt::meta::deref_return_t<Iter>...>;
using difference_type = blt::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
};
template<typename... Iter>
class zip_wrapper<std::bidirectional_iterator_tag, Iter...> : public zip_bidirectional_iterator<Iter...>
{
public:
using zip_bidirectional_iterator<Iter...>::zip_bidirectional_iterator;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = std::tuple<blt::meta::deref_return_t<Iter>...>;
using difference_type = blt::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
};
template<typename... Iter>
class zip_wrapper<std::random_access_iterator_tag, Iter...> : public zip_bidirectional_iterator<Iter...>
{
public:
using zip_bidirectional_iterator<Iter...>::zip_bidirectional_iterator;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = std::tuple<blt::meta::deref_return_t<Iter>...>;
using difference_type = blt::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
};
/** /**
* struct which is returned by the enumerator. * struct which is returned by the enumerator.
* @tparam T type to store. * @tparam T type to store.
@ -590,25 +478,6 @@ namespace blt
return CompleteEnumerator{b->begin(), b->end(), static_cast<blt::size_t>(std::distance(b->begin(), b->end()))}; return CompleteEnumerator{b->begin(), b->end(), static_cast<blt::size_t>(std::distance(b->begin(), b->end()))};
} }
}; };
template<typename... Iter>
class zip_iterator_storage<std::forward_iterator_tag, Iter...>
{
};
template<typename... Iter>
class zip_iterator_storage<std::bidirectional_iterator_tag, Iter...>
{
};
template<typename... Iter>
class zip_iterator_storage<std::random_access_iterator_tag, Iter...>
{
};
} }
/** /**

View File

@ -19,12 +19,158 @@
#ifndef BLT_ITERATOR_ZIP #ifndef BLT_ITERATOR_ZIP
#define BLT_ITERATOR_ZIP #define BLT_ITERATOR_ZIP
#include <blt/iterator/iter_common.h> #include <blt/iterator/common.h>
#include <blt/meta/meta.h>
#include <blt/meta/iterator.h>
#include <tuple> #include <tuple>
namespace blt namespace blt
{ {
namespace iterator
{
template<typename... Iter>
struct zip_wrapper : public base_wrapper<zip_wrapper<Iter...>>
{
public:
using iterator_category = meta::lowest_iterator_category_t<Iter...>;
using value_type = std::tuple<meta::deref_return_t<Iter>...>;
using difference_type = blt::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
explicit zip_wrapper(std::tuple<Iter...> iter): iter(std::move(iter))
{}
explicit zip_wrapper(Iter... iter): iter(std::make_tuple(iter...))
{}
std::tuple<meta::deref_return_t<Iter>...> operator*() const
{
return std::apply([](auto& ... i) { return std::tuple<meta::deref_return_t<Iter>...>{*i...}; }, iter);
}
zip_wrapper& operator++()
{
std::apply([](auto& ... i) { ((++i), ...); }, iter);
return *this;
}
zip_wrapper& operator--()
{
std::apply([](auto& ... i) { ((--i), ...); }, this->iter);
return *this;
}
friend zip_wrapper operator+(const zip_wrapper& a, blt::ptrdiff_t n)
{
static_assert(std::is_same_v<iterator_category, std::random_access_iterator_tag>,
"Iterator must allow random access");
return std::apply([n](auto& ... i) { return zip_wrapper((i + n)...); }, a.iter);
}
friend zip_wrapper operator-(const zip_wrapper& a, blt::ptrdiff_t n)
{
static_assert(std::is_same_v<iterator_category, std::random_access_iterator_tag>,
"Iterator must allow random access");
return std::apply([n](auto& ... i) { return zip_wrapper((i - n)...); }, a.iter);
}
friend blt::ptrdiff_t operator-(const zip_wrapper& a, const zip_wrapper& b)
{
return sub(a, b, std::index_sequence_for<Iter...>());
}
auto base() const
{
return iter;
}
protected:
std::tuple<Iter...> iter;
template<typename T, T... n>
static blt::ptrdiff_t sub(const zip_wrapper& a, const zip_wrapper& b,
std::integer_sequence<T, n...>)
{
blt::ptrdiff_t min = std::numeric_limits<blt::ptrdiff_t>::max();
((min = std::min(min, std::get<n>(a.iter) - std::get<n>(b.iter))), ...);
return min;
}
};
// template<typename Iter>
// struct zip_wrapper<Iter> : public Iter
// {
// using iterator_category = typename std::iterator_traits<Iter>::iterator_category;
// using value_type = typename std::iterator_traits<Iter>::value_type;
// using difference_type = typename std::iterator_traits<Iter>::difference_type;
// using pointer = typename std::iterator_traits<Iter>::pointer;
// using reference = typename std::iterator_traits<Iter>::reference;
//
// using Iter::Iter;
// };
}
template<typename Iter>
struct iterator_pair
{
using type = Iter;
iterator_pair(Iter begin, Iter end): begin(std::move(begin)), end(std::move(end))
{}
Iter begin;
Iter end;
};
template<typename... Iter>
class zip_iterator_container : public iterator::iterator_container<iterator::zip_wrapper<Iter...>>
{
public:
using iterator::iterator_container<iterator::zip_wrapper<Iter...>>::iterator_container;
explicit zip_iterator_container(iterator_pair<Iter>... iterator_pairs):
iterator::iterator_container<iterator::zip_wrapper<Iter...>>(iterator::zip_wrapper<Iter...>{std::move(iterator_pairs.begin)...},
iterator::zip_wrapper<Iter...>{std::move(iterator_pairs.end)...})
{}
};
namespace impl
{
template<typename Derived>
class zip_t
{
public:
template<typename... Iter>
auto zip(iterator_pair<Iter>... iterator_pairs)
{
auto* d = static_cast<Derived*>(this);
return zip_iterator_container(iterator_pair<decltype(d->begin())>{d->begin(), d->end()}, iterator_pairs...);
}
};
}
/*
* CTAD for the zip containers
*/
template<typename... Iter>
zip_iterator_container(iterator_pair<Iter>...) -> zip_iterator_container<Iter...>;
template<typename... Iter>
zip_iterator_container(std::initializer_list<Iter>...) -> zip_iterator_container<Iter...>;
/*
* Helper functions for creating zip containers
*/
template<typename... Container>
auto zip(Container& ... container)
{
return zip_iterator_container{iterator_pair{container.begin(), container.end()}...};
}
} }
#endif //BLT_ITERATOR_ZIP #endif //BLT_ITERATOR_ZIP

View File

@ -24,27 +24,71 @@
namespace blt::meta namespace blt::meta
{ {
template<typename Category>
struct is_input_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::input_iterator_tag>;
};
template<typename Category>
struct is_forward_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::forward_iterator_tag>;
};
template<typename Category>
struct is_bidirectional_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::bidirectional_iterator_tag>;
};
template<typename Category>
struct is_random_access_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::random_access_iterator_tag>;
};
template<typename Iter>
inline constexpr bool is_input_iterator_category_v = is_input_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_forward_iterator_category_v = is_forward_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_bidirectional_iterator_category_v = is_bidirectional_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_random_access_iterator_category_v = is_random_access_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_bidirectional_or_better_category_v =
is_bidirectional_iterator_category_v<Iter> || is_random_access_iterator_category_v<Iter>;
// this is required! :/ // this is required! :/
template<typename Iter> template<typename Iter>
struct is_input_iterator { struct is_input_iterator
constexpr static bool value = std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::input_iterator_tag>; {
constexpr static bool value = is_input_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
}; };
template<typename Iter> template<typename Iter>
struct is_forward_iterator { struct is_forward_iterator
constexpr static bool value = std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::forward_iterator_tag>; {
constexpr static bool value = is_forward_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
}; };
template<typename Iter> template<typename Iter>
struct is_bidirectional_iterator { struct is_bidirectional_iterator
constexpr static bool value = std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::bidirectional_iterator_tag>; {
constexpr static bool value = is_bidirectional_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
}; };
template<typename Iter> template<typename Iter>
struct is_random_access_iterator { struct is_random_access_iterator
constexpr static bool value = std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::random_access_iterator_tag>; {
constexpr static bool value = is_random_access_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
}; };
template<typename Iter> template<typename Iter>
@ -61,6 +105,27 @@ namespace blt::meta
template<typename Iter> template<typename Iter>
inline constexpr bool is_bidirectional_or_better_v = is_bidirectional_iterator_v<Iter> || is_random_access_iterator_v<Iter>; inline constexpr bool is_bidirectional_or_better_v = is_bidirectional_iterator_v<Iter> || is_random_access_iterator_v<Iter>;
template<typename... Iter>
struct lowest_iterator_category
{
using type = std::common_type_t<typename std::iterator_traits<Iter>::iterator_category...>;
};
template<typename... Iter>
using lowest_iterator_category_t = typename lowest_iterator_category<Iter...>::type;
template<typename Iter>
struct is_reverse_iterator : std::false_type
{
};
template<typename Iter>
struct is_reverse_iterator<std::reverse_iterator<Iter>> : std::true_type
{};
template<typename Iter>
inline constexpr bool is_reverse_iterator_v = is_reverse_iterator<Iter>::value;
} }
#endif //BLT_META_ITERATOR_H #endif //BLT_META_ITERATOR_H

View File

@ -22,7 +22,7 @@
#include <limits> #include <limits>
#include <vector> #include <vector>
#include <blt/std/ranges.h> #include <blt/std/ranges.h>
#include <blt/std/iterator.h> #include <blt/iterator/iterator.h>
#include <blt/std/utility.h> #include <blt/std/utility.h>
#include <blt/std/types.h> #include <blt/std/types.h>
#include <blt/std/assert.h> #include <blt/std/assert.h>
@ -159,10 +159,10 @@ namespace blt
*/ */
inline std::optional<block_view> search_for_block(block_storage* blk, size_t n) inline std::optional<block_view> search_for_block(block_storage* blk, size_t n)
{ {
for (auto kv : blt::enumerate(blk->unallocated_blocks)) for (auto [index, item] : blt::enumerate(blk->unallocated_blocks))
{ {
if (kv.second.n >= n) if (item.n >= n)
return block_view{blk, kv.first, kv.second.n - n}; return block_view{blk, index, item.n - n};
} }
return {}; return {};
} }

View File

@ -1,499 +0,0 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_ITERATOR_H
#define BLT_ITERATOR_H
#include <blt/std/types.h>
#include <blt/std/logging.h>
#include <blt/meta/meta.h>
#include <blt/meta/iterator.h>
#include <type_traits>
#include <iterator>
namespace blt
{
// forward declare useful types
template<typename Iter, typename = std::void_t<>>
class enumerator;
template<typename Iter, typename = std::void_t<>>
class enumerator_rev;
namespace iterator
{
template<typename Iter, typename = std::void_t<>>
class enumerate_wrapper;
/**
* struct which is returned by the enumerator.
* @tparam T type to store.
*/
template<typename T>
struct enumerate_item
{
blt::size_t index;
T value;
};
/**
* base class for iterators which operate on pairs of values. Handles comparison.
* @tparam Iter1 first iterator type. this will be used for comparison.
* @tparam Iter2 second iterator type. this value is not modified by this class.
*/
template<typename Iter1, typename Iter2>
class pair_iterator_base
{
public:
explicit pair_iterator_base(Iter1 iter1, Iter2 iter2): m_iter1(std::move(iter1)), m_iter2(std::move(iter2))
{}
friend bool operator==(const pair_iterator_base& a, const pair_iterator_base& b)
{
return a.m_iter1 == b.m_iter1;
}
friend bool operator!=(const pair_iterator_base& a, const pair_iterator_base& b)
{
return a.m_iter1 != b.m_iter1;
}
auto iter1() const
{
return m_iter1;
}
auto iter2() const
{
return m_iter2;
}
protected:
Iter1 m_iter1;
Iter2 m_iter2;
};
/**
* Base class for all enumerator iterators. Handles the deference (*) operator.
* @tparam Iter iterator type
*/
template<typename Iter>
class enumerate_iterator_base : public pair_iterator_base<Iter, blt::size_t>
{
public:
explicit enumerate_iterator_base(Iter iter, blt::size_t place = 0):
pair_iterator_base<Iter, blt::size_t>(std::move(iter), place)
{}
enumerate_item<blt::meta::deref_return_t<Iter>> operator*() const
{
return {this->m_iter2, *this->m_iter1};
}
auto base() const
{
return this->iter1();
}
auto get_index() const
{
return this->iter2();
}
};
/**
* Forward iterator base class for the enumerator. Contains the ++ operator.
* @tparam Iter iterator type.
*/
template<typename Iter>
class enumerate_forward_iterator : public enumerate_iterator_base<Iter>
{
public:
using enumerate_iterator_base<Iter>::enumerate_iterator_base;
enumerate_forward_iterator& operator++()
{
++this->m_iter1;
++this->m_iter2;
return *this;
}
enumerate_forward_iterator operator++(int)
{
auto tmp = *this;
++*this;
return tmp;
}
};
/**
* Bidirectional iterator base class for the enumerator. Contains the -- operator.
* @tparam Iter iterator type.
*/
template<typename Iter>
class enumerate_bidirectional_iterator : public enumerate_forward_iterator<Iter>
{
public:
using enumerate_forward_iterator<Iter>::enumerate_forward_iterator;
enumerate_bidirectional_iterator& operator--()
{
--this->m_iter1;
--this->m_iter2;
return *this;
}
enumerate_bidirectional_iterator operator--(int)
{
auto tmp = *this;
--*this;
return tmp;
}
};
/**
* Wrapper class specialization for forward iterators.
* @tparam Iter iterator type
*/
template<typename Iter>
class enumerate_wrapper<Iter, std::enable_if_t<blt::meta::is_forward_iterator_v<Iter>, std::void_t<std::forward_iterator_tag>>>
: public enumerate_forward_iterator<Iter>
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = enumerate_item<blt::meta::deref_return_t<Iter>>;
using difference_type = typename std::iterator_traits<Iter>::difference_type;
using pointer = value_type;
using reference = value_type;
using iterator_type = Iter;
using enumerate_forward_iterator<Iter>::enumerate_forward_iterator;
};
/**
* Wrapper class for bidirectional iterators or random access iterators.
* @tparam Iter iterator type.
*/
template<typename Iter>
class enumerate_wrapper<Iter, std::enable_if_t<blt::meta::is_bidirectional_or_better_v<Iter>, std::void_t<std::bidirectional_iterator_tag>>>
: public enumerate_bidirectional_iterator<Iter>
{
public:
using iterator_category = typename std::iterator_traits<Iter>::iterator_category;
using value_type = enumerate_item<blt::meta::deref_return_t<Iter>>;
using difference_type = typename std::iterator_traits<Iter>::difference_type;
using pointer = value_type;
using reference = value_type;
using iterator_type = Iter;
using enumerate_bidirectional_iterator<Iter>::enumerate_bidirectional_iterator;
};
/**
* Base class for the enumerator. Holds the begin and end iterators.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate (enumerate_wrapper)
*/
template<typename Iter, typename IterWrapper>
class enumerator_base
{
public:
explicit enumerator_base(Iter begin, Iter end): begin_(std::move(begin)), end_(std::move(end))
{}
explicit enumerator_base(IterWrapper begin, IterWrapper end): begin_(std::move(begin)), end_(std::move(end))
{}
auto begin()
{
return begin_;
}
auto end()
{
return end_;
}
/**
* Creates an enumerator that skips the first n elements.
* @param amount amount of values to skip.
*/
auto skip(blt::size_t amount)
{
auto begin = this->begin_;
for (blt::size_t i = 0; i < amount; i++)
++begin;
return enumerator<Iter>{begin.base(),
this->end_.base(),
begin.get_index(),
this->end_.get_index()};
}
/**
* Creates an enumerator that yields the first n elements, or UB if the underlying iterator ends sooner.
* @param amount amount to take.
*/
auto take(blt::size_t amount)
{
auto end = this->begin();
for (blt::size_t i = 0; i < amount; i++)
++end;
return enumerator<Iter>{this->begin_.base(),
end.base(),
this->begin_.get_index(),
end.get_index()};
}
protected:
IterWrapper begin_;
IterWrapper end_;
};
/**
* Reversible (bidirectional) base class for the enumerator.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate (enumerate_wrapper).
*/
template<typename Iter, typename IterWrapper>
class enumerator_reversible : public enumerator_base<Iter, IterWrapper>
{
public:
explicit enumerator_reversible(Iter begin, Iter end, blt::size_t container_size):
enumerator_base<Iter, IterWrapper>{IterWrapper{enumerate_wrapper<Iter>{std::move(begin), 0}},
IterWrapper{enumerate_wrapper<Iter>{std::move(end), container_size}}}
{}
explicit enumerator_reversible(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
enumerator_base<Iter, IterWrapper>(IterWrapper{enumerate_wrapper<Iter>{std::move(begin), begin_index}},
IterWrapper{enumerate_wrapper<Iter>{std::move(end), end_index}})
{}
/**
* Reverses the enumerators direction.
*/
auto rev() const
{
return enumerator_rev<Iter>{this->end_.base(),
this->begin_.base(),
this->end_.get_index(),
this->begin_.get_index()};
}
};
/**
* Random access base class for the enumerator. Has updated skip and take methods which make use of the random access nature of the iterator.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate (enumerate_wrapper).
*/
template<typename Iter, typename IterWrapper>
class enumerator_random_access : public enumerator_reversible<Iter, IterWrapper>
{
public:
using enumerator_reversible<Iter, IterWrapper>::enumerator_reversible;
auto skip(blt::size_t amount)
{
return enumerator<Iter>{this->begin_.base() + amount,
this->end_.base(),
this->begin_.get_index() + amount,
this->end_.get_index()};
}
auto take(blt::size_t amount)
{
return enumerator<Iter>{this->begin_.base(),
this->begin_.base() + amount,
this->begin_.get_index(),
this->begin_.get_index() + amount};
}
};
/**
* Reversible (bidirectional) base class for the enumerator, operates in reverse for reverse enumeration.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate (std::reverse_iterator<enumerate_wrapper>).
*/
template<typename Iter, typename IterWrapper>
class enumerator_reversible_rev : public enumerator_reversible<Iter, IterWrapper>
{
public:
using enumerator_reversible<Iter, IterWrapper>::enumerator_reversible;
auto rev() const
{
return enumerator<Iter>{this->end_.base().base(),
this->begin_.base().base(),
this->end_.base().get_index(),
this->begin_.base().get_index()};
}
auto skip(blt::size_t amount)
{
auto begin = this->begin_.base();
for (blt::size_t i = 0; i < amount; i++)
--begin;
return enumerator_rev<Iter>{begin.base(),
this->end_.base().base(),
begin.get_index(),
this->end_.base().get_index()};
}
auto take(blt::size_t amount)
{
auto end = this->begin_.base();
for (blt::size_t i = 0; i < amount; i++)
--end;
return enumerator_rev<Iter>{
this->begin_.base().base(),
end.base(),
this->begin_.base().get_index(),
end.get_index()};
}
};
/**
* Random access base class for the enumerator. Has updated skip and take methods which make use of the random access nature of the iterator.
* Operates in reverse for reverse enumeration.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate (std::reverse_iterator<enumerate_wrapper>).
*/
template<typename Iter, typename IterWrapper>
class enumerator_random_access_rev : public enumerator_reversible_rev<Iter, IterWrapper>
{
public:
using enumerator_reversible_rev<Iter, IterWrapper>::enumerator_reversible_rev;
auto skip(blt::size_t amount)
{
return enumerator_rev<Iter>{this->begin_.base().base() - amount,
this->end_.base().base(),
this->begin_.base().get_index() - amount,
this->end_.base().get_index()};
}
auto take(blt::size_t amount)
{
return enumerator_rev<Iter>{this->begin_.base().base(),
this->begin_.base().base() - amount,
this->begin_.base().get_index(),
this->begin_.base().get_index() - amount};
}
};
}
/**
* Enumerator specialization for forward iterators
*/
template<typename Iter>
class enumerator<Iter, std::enable_if_t<blt::meta::is_forward_iterator_v<Iter>, std::void_t<std::forward_iterator_tag>>>
: public iterator::enumerator_base<Iter, iterator::enumerate_wrapper<Iter>>
{
public:
using iterator::enumerator_base<Iter, iterator::enumerate_wrapper<Iter>>::enumerator_base;
};
/**
* Enumerator specialization for bidirectional iterators
*/
template<typename Iter>
class enumerator<Iter, std::enable_if_t<blt::meta::is_bidirectional_iterator_v<Iter>, std::void_t<std::bidirectional_iterator_tag>>>
: public iterator::enumerator_reversible<Iter, iterator::enumerate_wrapper<Iter>>
{
public:
using iterator::enumerator_reversible<Iter, iterator::enumerate_wrapper<Iter>>::enumerator_reversible;
};
/**
* Enumerator specialization for random access iterators
*/
template<typename Iter>
class enumerator<Iter, std::enable_if_t<blt::meta::is_random_access_iterator_v<Iter>, std::void_t<std::random_access_iterator_tag>>>
: public iterator::enumerator_random_access<Iter, iterator::enumerate_wrapper<Iter>>
{
public:
using iterator::enumerator_random_access<Iter, iterator::enumerate_wrapper<Iter>>::enumerator_random_access;
};
/**
* Reverse enumerator specialization for bidirectional iterators
*/
template<typename Iter>
class enumerator_rev<Iter, std::enable_if_t<blt::meta::is_bidirectional_iterator_v<Iter>, std::void_t<std::bidirectional_iterator_tag>>>
: public iterator::enumerator_reversible_rev<Iter, std::reverse_iterator<iterator::enumerate_wrapper<Iter>>>
{
public:
using iterator::enumerator_reversible_rev<Iter, std::reverse_iterator<iterator::enumerate_wrapper<Iter>>>::enumerator_reversible_rev;
};
/**
* Reverse enumerator specialization for random access iterators
*/
template<typename Iter>
class enumerator_rev<Iter, std::enable_if_t<blt::meta::is_random_access_iterator_v<Iter>, std::void_t<std::random_access_iterator_tag>>>
: public iterator::enumerator_random_access_rev<Iter, std::reverse_iterator<iterator::enumerate_wrapper<Iter>>>
{
public:
using iterator::enumerator_random_access_rev<Iter, std::reverse_iterator<iterator::enumerate_wrapper<Iter>>>::enumerator_random_access_rev;
};
// CTAD for enumerators
template<typename Iter>
enumerator(Iter, Iter) -> enumerator<Iter>;
template<typename Iter>
enumerator(Iter, Iter, blt::size_t) -> enumerator<Iter>;
template<typename Iter>
enumerator(Iter, Iter, blt::size_t, blt::size_t) -> enumerator<Iter>;
template<typename T, blt::size_t size>
static inline auto enumerate(const T(& container)[size])
{
return enumerator{&container[0], &container[size], size};
}
template<typename T, blt::size_t size>
static inline auto enumerate(T(& container)[size])
{
return enumerator{&container[0], &container[size], size};
}
template<typename T>
static inline auto enumerate(T& container)
{
return enumerator{container.begin(), container.end(), container.size()};
}
template<typename T>
static inline auto enumerate(T&& container)
{
return enumerator{container.begin(), container.end(), container.size()};
}
template<typename T>
static inline auto enumerate(const T& container)
{
return enumerator{container.begin(), container.end(), container.size()};
}
}
#endif //BLT_ITERATOR_H

View File

@ -174,6 +174,12 @@ namespace blt::random
return BLT_RANDOM_FUNCTION(seed, min, max); return BLT_RANDOM_FUNCTION(seed, min, max);
} }
template<typename T>
constexpr T get(T min, T max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
constexpr bool choice() constexpr bool choice()
{ {
return BLT_RANDOM_DOUBLE(seed) < 0.5; return BLT_RANDOM_DOUBLE(seed) < 0.5;

View File

@ -134,35 +134,35 @@ namespace blt
iterator<C1_ITER, C2_ITER> end_; iterator<C1_ITER, C2_ITER> end_;
}; };
template<typename T, typename G> // template<typename T, typename G>
static inline auto in_pairs(const T& container1, const G& container2) // static inline auto in_pairs(const T& container1, const G& container2)
{ // {
return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()}; // return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
} // }
//
template<typename T, typename G> // template<typename T, typename G>
static inline auto in_pairs(T& container1, G& container2) // static inline auto in_pairs(T& container1, G& container2)
{ // {
return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()}; // return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
} // }
//
template<typename T, typename G, blt::size_t size> // template<typename T, typename G, blt::size_t size>
static inline auto in_pairs(const T(& container1)[size], const G(& container2)[size]) // static inline auto in_pairs(const T(& container1)[size], const G(& container2)[size])
{ // {
return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]}; // return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]};
} // }
//
template<typename T, typename G, blt::size_t size> // template<typename T, typename G, blt::size_t size>
static inline auto in_pairs(T(& container1)[size], G(& container2)[size]) // static inline auto in_pairs(T(& container1)[size], G(& container2)[size])
{ // {
return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]}; // return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]};
} // }
//
template<typename T, typename G> // template<typename T, typename G>
static inline auto in_pairs(T&& container1, G&& container2) // static inline auto in_pairs(T&& container1, G&& container2)
{ // {
return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()}; // return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
} // }
template<typename T> template<typename T>
struct range struct range

View File

@ -42,8 +42,8 @@ namespace blt
using pointer = T*; using pointer = T*;
using const_reference = const T&; using const_reference = const T&;
using const_pointer = const T*; using const_pointer = const T*;
using iterator = blt::ptr_iterator<T>; using iterator = T*;
using const_iterator = blt::ptr_iterator<const T>; using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
public: public:
@ -131,24 +131,24 @@ namespace blt
return buffer_[index]; return buffer_[index];
} }
constexpr inline pointer operator*() constexpr inline reference operator*()
{ {
return buffer_; return *buffer_.data();
} }
constexpr inline const_pointer operator*() const constexpr inline const_reference operator*() const
{ {
return buffer_; return *buffer_.data();
} }
constexpr inline pointer data() constexpr inline pointer data()
{ {
return buffer_; return buffer_.data();
} }
constexpr inline const_pointer data() const constexpr inline const_pointer data() const
{ {
return buffer_; return buffer_.data();
} }
constexpr inline reference front() constexpr inline reference front()
@ -290,8 +290,8 @@ namespace blt
using const_reference = const value_type&; using const_reference = const value_type&;
using pointer = value_type*; using pointer = value_type*;
using const_pointer = const pointer; using const_pointer = const pointer;
using iterator = blt::ptr_iterator<T>; using iterator = T*;
using const_iterator = blt::ptr_iterator<const T>; using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>; using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;

View File

@ -6,7 +6,7 @@
#include <blt/parse/argparse.h> #include <blt/parse/argparse.h>
#include <iostream> #include <iostream>
#include <blt/std/string.h> #include <blt/std/string.h>
#include <blt/std/iterator.h> #include <blt/iterator/iterator.h>
#include <algorithm> #include <algorithm>
#include "blt/std/utility.h" #include "blt/std/utility.h"

View File

@ -21,7 +21,7 @@
#include <blt/parse/obj_loader.h> #include <blt/parse/obj_loader.h>
#include <blt/fs/loader.h> #include <blt/fs/loader.h>
#include <blt/std/string.h> #include <blt/std/string.h>
#include <blt/std/iterator.h> #include <blt/iterator/iterator.h>
#include <cctype> #include <cctype>
#include <charconv> #include <charconv>
#include "blt/std/assert.h" #include "blt/std/assert.h"

168
tests/iterator_tests.cpp Normal file
View File

@ -0,0 +1,168 @@
/*
* <Short Description>
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <blt/std/logging.h>
#include <blt/std/types.h>
#include <blt/std/assert.h>
#include <blt/math/vectors.h>
#include <blt/math/log_util.h>
#include <blt/iterator/zip.h>
#include <blt/iterator/enumerate.h>
#include <blt/iterator/iterator.h>
#include <blt/format/boxing.h>
#include <array>
#include <forward_list>
constexpr auto increasing_reverse_pairs =
[](blt::size_t i, blt::size_t index, blt::size_t size) { return i == 0 ? index : (size - 1) - index; };
constexpr auto increasing_pairs =
[](blt::size_t, blt::size_t index, blt::size_t) { return index; };
constexpr auto decreasing_pairs =
[](blt::size_t, blt::size_t index, blt::size_t size) { return size - index; };
template<blt::size_t n, typename Func>
std::array<blt::vec2, n> make_array(Func func)
{
std::array<blt::vec2, n> array;
for (auto&& [index, value] : blt::enumerate(array))
value = blt::vec2(func(0, index, n), func(1, index, n));
return array;
}
template<blt::size_t n, typename Func>
std::forward_list<blt::vec2> make_list(Func func)
{
std::forward_list<blt::vec2> array;
for (auto index : blt::range(0ul, n))
array.push_front(blt::vec2(func(0, index, n), func(1, index, n)));
return array;
}
constexpr blt::size_t array_size = 10;
auto array_1 = make_array<array_size>(increasing_reverse_pairs);
auto array_2 = make_array<array_size>(increasing_pairs);
auto array_3 = make_array<array_size>(decreasing_pairs);
auto list_1 = make_list<array_size>(increasing_reverse_pairs);
void test_enumerate()
{
blt::log_box_t box(std::cout, "Enumerate Tests", 25);
for (const auto& [index, item] : blt::enumerate(array_1))
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).rev())
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).take(3))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index < 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).take(3).rev())
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index < 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3).rev())
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3).take(5))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 3 && index < (array_1.size() - 5) + 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3).rev().take(5))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 5);
}
}
void test_pairs()
{
blt::log_box_t box(std::cout, "Pairs Tests", 25);
}
void test_zip()
{
blt::log_box_t box(std::cout, "Zip Tests", 25);
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, list_1))
{
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
}
BLT_TRACE("================================");
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, list_1).take(3))
{
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
}
BLT_TRACE("================================");
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).take(3).rev())
{
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
}
BLT_TRACE("================================");
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).take_or(13))
{
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
}
BLT_TRACE("================================");
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).rev().take(3))
{
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
}
BLT_TRACE("================================");
for (auto [a1, a2, a3] : blt::zip(array_1, array_2, array_3).skip(2).rev())
{
BLT_TRACE_STREAM << a1 << " : " << a2 << " : " << a3 << "\n";
}
}
int main()
{
test_enumerate();
std::cout << std::endl;
test_pairs();
std::cout << std::endl;
test_zip();
}

View File

@ -28,8 +28,8 @@ namespace blt::test
void print(const T& ref) void print(const T& ref)
{ {
BLT_TRACE_STREAM << "(" << ref.size() << ") ["; BLT_TRACE_STREAM << "(" << ref.size() << ") [";
for (auto v : blt::enumerate(ref)) for (auto [index, item] : blt::enumerate(ref))
BLT_TRACE_STREAM << v.second << ((v.first != ref.size()-1) ? ", " : "]\n"); BLT_TRACE_STREAM << item << ((index != ref.size()-1) ? ", " : "]\n");
} }
void vector_run() void vector_run()

View File

@ -7,7 +7,7 @@
#include <blt/fs/nbt.h> #include <blt/fs/nbt.h>
#include <blt/profiling/profiler.h> #include <blt/profiling/profiler.h>
#include <blt/std/logging.h> #include <blt/std/logging.h>
#include <blt/std/format.h> #include <blt/format/format.h>
#include <blt/fs/filesystem.h> #include <blt/fs/filesystem.h>
#include <filesystem> #include <filesystem>

View File

@ -15,7 +15,7 @@ namespace blt::tests {
template<typename T> template<typename T>
T* generateRandomData(T* arr, size_t size, uint32_t seed = 0) { T* generateRandomData(T* arr, size_t size, uint32_t seed = 0) {
for (size_t i = 0; i < size; i++) for (size_t i = 0; i < size; i++)
arr[i] = blt::random::randomInt_c(i * size + seed, std::numeric_limits<T>::min(), std::numeric_limits<T>::max()); arr[i] = blt::random::random_t(i * size + seed).get(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
return arr; return arr;
} }

View File

@ -10,7 +10,7 @@
#include "blt/profiling/profiler_v2.h" #include "blt/profiling/profiler_v2.h"
#include "blt/std/logging.h" #include "blt/std/logging.h"
#include "blt/std/time.h" #include "blt/std/time.h"
#include "blt/std/format.h" #include "blt/format/format.h"
void print(const std::vector<std::string>& vtr) { void print(const std::vector<std::string>& vtr) {
for (const auto& line : vtr) for (const auto& line : vtr)

View File

@ -19,6 +19,7 @@
#include <blt/std/utility.h> #include <blt/std/utility.h>
#include <blt/std/string.h> #include <blt/std/string.h>
#include <blt/std/logging.h> #include <blt/std/logging.h>
#include <blt/iterator/iterator.h>
namespace blt::test namespace blt::test
{ {
@ -32,27 +33,27 @@ namespace blt::test
auto sv_splits_c = blt::string::split_sv(str, ' '); auto sv_splits_c = blt::string::split_sv(str, ' ');
auto sv_splits_s = blt::string::split_sv(str, "LOT"); auto sv_splits_s = blt::string::split_sv(str, "LOT");
for (auto v : blt::enumerate(s_splits_c)) for (auto [index, item] : blt::enumerate(s_splits_c))
{ {
if (v.second != sv_splits_c[v.first]) if (item != sv_splits_c[index])
{ {
BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", v.second.c_str(), std::string(sv_splits_c[v.first]).c_str()); BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", item.c_str(), std::string(sv_splits_c[index]).c_str());
} else } else
{ {
BLT_DEBUG(v.second); BLT_DEBUG(item);
} }
} }
BLT_INFO(""); BLT_INFO("");
for (auto v : blt::enumerate(s_splits_s)) for (auto [index, item] : blt::enumerate(s_splits_s))
{ {
if (v.second != sv_splits_s[v.first]) if (item != sv_splits_s[index])
{ {
BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", v.second.c_str(), std::string(sv_splits_s[v.first]).c_str()); BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", item.c_str(), std::string(sv_splits_s[index]).c_str());
} else } else
{ {
BLT_DEBUG(v.second); BLT_DEBUG(item);
} }
} }
} }

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
#include <blt/std/utility.h> #include <blt/std/utility.h>
#include <blt/std/format.h> #include <blt/format/format.h>
#include <blt/std/logging.h> #include <blt/std/logging.h>
#include <blt/profiling/profiler_v2.h> #include <blt/profiling/profiler_v2.h>
#include <utility_test.h> #include <utility_test.h>