diff --git a/.idea/misc.xml b/.idea/misc.xml
index 79b3c94..0b76fe5 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,4 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..887d4ca
--- /dev/null
+++ b/.vscode/launch.json
@@ -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
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..d3f548b
--- /dev/null
+++ b/.vscode/settings.json
@@ -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"
+ }
+}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 44a26ae..29decc6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,6 @@
cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake)
-set(BLT_VERSION 0.21.3)
-set(BLT_TEST_VERSION 0.0.1)
+set(BLT_VERSION 1.1.7)
set(BLT_TARGET BLT)
@@ -34,6 +33,8 @@ if(${BLT_DISABLE_STATS})
add_compile_definitions(BLT_DISABLE_STATS)
endif ()
+find_program(MOLD "mold")
+
configure_file(include/blt/config.h.in config/blt/config.h @ONLY)
message("Enabling library compilation")
@@ -138,30 +139,64 @@ 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 SOVERSION ${PROJECT_VERSION_MAJOR})
+if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND)
+ target_link_options(${BLT_TARGET} PUBLIC -fuse-ld=mold)
+endif ()
install(TARGETS ${BLT_TARGET}
CONFIGURATIONS RelWithDebInfo
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
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})
- message("Building test version ${BLT_TEST_VERSION}")
- project(BLT_TESTS VERSION ${BLT_TEST_VERSION})
+ message("Building tests for version ${BLT_VERSION}")
- include_directories(tests/include)
-
- 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)
+ blt_add_project(blt-iterator tests/iterator_tests.cpp test)
message("Built tests")
endif ()
-project(BLT)
\ No newline at end of file
+project(BLT)
diff --git a/commit.py b/commit.py
index e8b8443..00d0d95 100755
--- a/commit.py
+++ b/commit.py
@@ -1,6 +1,13 @@
#!/usr/bin/python3
import subprocess
+import argparse
+import sys
+import os
+import itertools
+import requests
+import json
+from pathlib import Path
#---------------------------------------
# CONFIG
@@ -8,12 +15,110 @@ import subprocess
VERSION_BEGIN_STR = "set(BLT_VERSION "
VERSION_END_STR = ")"
-PATCH_LIMIT = 1000
#---------------------------------------
# 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():
cmake_file = open("CMakeLists.txt", 'r')
cmake_text = cmake_file.read()
@@ -38,9 +143,8 @@ def split_version(cmake_text):
def recombine(cmake_text, version_parts, begin, end):
constructed_version = version_parts[0] + '.' + version_parts[1] + '.' + version_parts[2]
constructed_text_begin = cmake_text[0:begin]
- constrcuted_text_end = cmake_text[end::]
- return constructed_text_begin + constructed_version + constrcuted_text_end
-
+ constructed_text_end = cmake_text[end::]
+ return constructed_text_begin + constructed_version + constructed_text_end
def inc_major(cmake_text):
version_parts, begin, end = split_version(cmake_text)
@@ -55,32 +159,158 @@ def inc_minor(cmake_text):
version_parts[2] = '0'
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)
- 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)
version_parts[2] = str(int(version_parts[2]) + 1)
return recombine(cmake_text, version_parts, begin, end)
-cmake_text = load_cmake()
-cmake_version = get_version(cmake_text)[0]
-print(f"Current Version: {cmake_version}")
+def make_branch(config: Config, name):
+ print(f"Making new branch {name}")
+ subprocess.call(["git", "checkout", "-b", name])
+ subprocess.call(["git", "merge", config.main_branch])
+ subprocess.call(["git", "checkout", config.main_branch])
+
+def sync_branch(config: Config, version_parts, args):
+ if config.branch_on_major:
+ # Branch will be created.
+ if args.minor:
+ return;
-try:
- type = input("What kind of commit is this ((M)ajor, (m)inor, (p)atch)? ")
+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())
- if type.startswith('M'):
+
+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)? ")
+
+ 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")
write_cmake(inc_major(cmake_text))
- elif type.startswith('m'):
+ elif args.minor:
print("Selected minor")
write_cmake(inc_minor(cmake_text))
- elif type.startswith('p') or type.startswith('P') or len(type) == 0:
+ elif args.patch:
print("Selected patch")
- write_cmake(inc_patch(cmake_text))
+ write_cmake(inc_patch(config, cmake_text))
subprocess.call(["git", "add", "*"])
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"])
-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()
diff --git a/include/blt/iterator/common.h b/include/blt/iterator/common.h
new file mode 100644
index 0000000..50f3b55
--- /dev/null
+++ b/include/blt/iterator/common.h
@@ -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 .
+ */
+
+#ifndef BLT_ITERATOR_ITER_COMMON
+#define BLT_ITERATOR_ITER_COMMON
+
+#include
+#include
+#include
+
+namespace blt::iterator
+{
+ template
+ struct base_wrapper
+ {
+ base_wrapper operator++(int)
+ {
+ auto tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ base_wrapper operator--(int)
+ {
+ static_assert(std::is_same_v ||
+ std::is_same_v,
+ "Iterator must allow random access");
+ auto tmp = *this;
+ --*this;
+ return tmp;
+ }
+
+ auto operator[](blt::ptrdiff_t n) const
+ {
+ static_assert(std::is_same_v,
+ "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,
+ "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,
+ "Iterator must allow random access");
+ return b < a;
+ }
+
+ friend bool operator>=(const base_wrapper& a, base_wrapper& b)
+ {
+ static_assert(std::is_same_v,
+ "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,
+ "Iterator must allow random access");
+ return !(a > b); // NOLINT
+ }
+
+ friend bool operator==(const base_wrapper& a, const base_wrapper& b)
+ {
+ return static_cast(a).base() == static_cast(b).base();
+ }
+
+ friend bool operator!=(const base_wrapper& a, const base_wrapper& b)
+ {
+ return !(static_cast(a).base() == static_cast(b).base()); // NOLINT
+ }
+ };
+
+ template
+ struct passthrough_wrapper : public base_wrapper
+ {
+ 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
+ struct passthrough_wrapper : public passthrough_wrapper
+ {
+ using passthrough_wrapper::passthrough_wrapper;
+
+ meta::deref_return_t operator*() const
+ {
+ return *this->iter;
+ }
+ };
+
+ namespace impl
+ {
+ template
+ class skip_t
+ {
+ private:
+ template
+ auto skip_base(blt::size_t n)
+ {
+ auto* d = static_cast(this);
+ auto begin = d->begin();
+ auto end = d->end();
+
+ if constexpr (std::is_same_v ||
+ std::is_same_v)
+ {
+ 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)
+ {
+ // random access iterators can have math directly applied to them.
+ if constexpr (check)
+ {
+ return Derived{begin + std::min(static_cast(n), std::distance(begin, end)), end};
+ } else
+ {
+ return Derived{begin + n, end};
+ }
+ }
+ }
+
+ public:
+ auto skip(blt::size_t n)
+ { return skip_base(n); }
+
+ auto skip_or(blt::size_t n)
+ { return skip_base(n); }
+ };
+
+ template
+ class take_t
+ {
+ private:
+ template
+ auto take_base(blt::size_t n)
+ {
+ static_assert(!std::is_same_v,
+ "Cannot .take() on an input iterator!");
+ auto* d = static_cast(this);
+ auto begin = d->begin();
+ auto end = d->end();
+
+ // take variant for forward and bidirectional iterators
+ if constexpr (std::is_same_v ||
+ std::is_same_v)
+ {
+ // 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)
+ {
+ // random access iterators can have math directly applied to them.
+ if constexpr (check)
+ {
+ return Derived{begin, begin + std::min(static_cast(n), std::distance(begin, end))};
+ } else
+ {
+ return Derived{begin, begin + n};
+ }
+ }
+ }
+
+ public:
+ auto take(blt::size_t n)
+ { return take_base(n); }
+
+ auto take_or(blt::size_t n)
+ { return take_base(n); }
+ };
+ }
+
+ template
+ class iterator_container : public impl::take_t>,
+ public impl::skip_t>
+ {
+ 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
+ iterator_container(Iter&& begin, Iter&& end): m_begin(std::forward(begin)), m_end(std::forward(end))
+ {}
+
+ auto rev()
+ {
+ static_assert((std::is_same_v ||
+ std::is_same_v),
+ ".rev() must be used with bidirectional (or better) iterators!");
+ return iterator_container>{std::reverse_iterator{end()},
+ std::reverse_iterator{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
diff --git a/include/blt/iterator/enumerate.h b/include/blt/iterator/enumerate.h
new file mode 100644
index 0000000..3747a70
--- /dev/null
+++ b/include/blt/iterator/enumerate.h
@@ -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 .
+ */
+
+#ifndef BLT_ITERATOR_ENUMERATE_H
+#define BLT_ITERATOR_ENUMERATE_H
+
+#include
+#include
+#include
+
+namespace blt
+{
+
+ namespace iterator
+ {
+ /**
+ * struct which is returned by the enumerator.
+ * @tparam T type to store.
+ */
+ template
+ struct enumerate_item
+ {
+ blt::size_t index;
+ T value;
+ };
+
+ template
+ class enumerate_wrapper : public passthrough_wrapper>
+ {
+ public:
+ using passthrough_wrapper>::passthrough_wrapper;
+
+ enumerate_item> operator*() const
+ {
+ return *this->iter;
+ }
+ private:
+ blt::size_t index;
+ };
+ }
+
+}
+
+#endif //BLT_ITERATOR_ENUMERATE_H
diff --git a/include/blt/iterator/iterator.h b/include/blt/iterator/iterator.h
index 5f9e9a7..96400eb 100644
--- a/include/blt/iterator/iterator.h
+++ b/include/blt/iterator/iterator.h
@@ -21,7 +21,7 @@
#include
#include
-#include
+#include
#include
#include
#include
@@ -59,118 +59,6 @@ namespace blt
template>
class pair_wrapper;
- template
- class zip_wrapper;
-
- template
- class zip_iterator_storage;
-
- template
- class zip_iterator_storage_rev;
-
- template
- class zip_forward_iterator
- {
- public:
- explicit zip_forward_iterator(Iter... iter): iter(std::make_tuple(iter...))
- {}
-
- std::tuple...> 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;
- };
-
- template
- class zip_bidirectional_iterator : public zip_forward_iterator
- {
- public:
- using zip_forward_iterator::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
- class zip_wrapper : public zip_forward_iterator
- {
- public:
- using zip_forward_iterator::zip_forward_iterator;
-
- using iterator_category = std::forward_iterator_tag;
- using value_type = std::tuple...>;
- using difference_type = blt::ptrdiff_t;
- using pointer = value_type;
- using reference = value_type;
- };
-
- template
- class zip_wrapper : public zip_bidirectional_iterator
- {
- public:
- using zip_bidirectional_iterator::zip_bidirectional_iterator;
-
- using iterator_category = std::bidirectional_iterator_tag;
- using value_type = std::tuple...>;
- using difference_type = blt::ptrdiff_t;
- using pointer = value_type;
- using reference = value_type;
- };
-
- template
- class zip_wrapper : public zip_bidirectional_iterator
- {
- public:
- using zip_bidirectional_iterator::zip_bidirectional_iterator;
-
- using iterator_category = std::bidirectional_iterator_tag;
- using value_type = std::tuple...>;
- using difference_type = blt::ptrdiff_t;
- using pointer = value_type;
- using reference = value_type;
- };
-
/**
* struct which is returned by the enumerator.
* @tparam T type to store.
@@ -590,25 +478,6 @@ namespace blt
return CompleteEnumerator{b->begin(), b->end(), static_cast(std::distance(b->begin(), b->end()))};
}
};
-
- template
- class zip_iterator_storage
- {
-
- };
-
- template
- class zip_iterator_storage
- {
-
- };
-
- template
- class zip_iterator_storage
- {
-
- };
-
}
/**
diff --git a/include/blt/iterator/zip.h b/include/blt/iterator/zip.h
index f8f197d..1fec30d 100644
--- a/include/blt/iterator/zip.h
+++ b/include/blt/iterator/zip.h
@@ -19,12 +19,158 @@
#ifndef BLT_ITERATOR_ZIP
#define BLT_ITERATOR_ZIP
-#include
+#include
+#include
+#include
#include
namespace blt
{
+ namespace iterator
+ {
+ template
+ struct zip_wrapper : public base_wrapper>
+ {
+ public:
+ using iterator_category = meta::lowest_iterator_category_t;
+ using value_type = std::tuple...>;
+ using difference_type = blt::ptrdiff_t;
+ using pointer = value_type;
+ using reference = value_type;
+
+ explicit zip_wrapper(std::tuple iter): iter(std::move(iter))
+ {}
+
+ explicit zip_wrapper(Iter... iter): iter(std::make_tuple(iter...))
+ {}
+
+ std::tuple...> operator*() const
+ {
+ return std::apply([](auto& ... i) { return std::tuple...>{*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 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 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());
+ }
+
+ auto base() const
+ {
+ return iter;
+ }
+
+ protected:
+ std::tuple iter;
+
+ template
+ static blt::ptrdiff_t sub(const zip_wrapper& a, const zip_wrapper& b,
+ std::integer_sequence)
+ {
+ blt::ptrdiff_t min = std::numeric_limits::max();
+ ((min = std::min(min, std::get(a.iter) - std::get(b.iter))), ...);
+ return min;
+ }
+ };
+// template
+// struct zip_wrapper : public Iter
+// {
+// using iterator_category = typename std::iterator_traits::iterator_category;
+// using value_type = typename std::iterator_traits::value_type;
+// using difference_type = typename std::iterator_traits::difference_type;
+// using pointer = typename std::iterator_traits::pointer;
+// using reference = typename std::iterator_traits::reference;
+//
+// using Iter::Iter;
+// };
+ }
+
+ template
+ 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
+ class zip_iterator_container : public iterator::iterator_container>
+ {
+ public:
+ using iterator::iterator_container>::iterator_container;
+
+ explicit zip_iterator_container(iterator_pair... iterator_pairs):
+ iterator::iterator_container>(iterator::zip_wrapper{std::move(iterator_pairs.begin)...},
+ iterator::zip_wrapper{std::move(iterator_pairs.end)...})
+ {}
+
+ };
+
+ namespace impl
+ {
+ template
+ class zip_t
+ {
+ public:
+ template
+ auto zip(iterator_pair... iterator_pairs)
+ {
+ auto* d = static_cast(this);
+ return zip_iterator_container(iterator_pairbegin())>{d->begin(), d->end()}, iterator_pairs...);
+ }
+ };
+ }
+
+ /*
+ * CTAD for the zip containers
+ */
+
+ template
+ zip_iterator_container(iterator_pair...) -> zip_iterator_container;
+
+ template
+ zip_iterator_container(std::initializer_list...) -> zip_iterator_container;
+
+
+ /*
+ * Helper functions for creating zip containers
+ */
+
+ template
+ auto zip(Container& ... container)
+ {
+ return zip_iterator_container{iterator_pair{container.begin(), container.end()}...};
+ }
}
#endif //BLT_ITERATOR_ZIP
diff --git a/include/blt/meta/iterator.h b/include/blt/meta/iterator.h
index e5873f6..e7df5a7 100644
--- a/include/blt/meta/iterator.h
+++ b/include/blt/meta/iterator.h
@@ -24,27 +24,71 @@
namespace blt::meta
{
+ template
+ struct is_input_iterator_category
+ {
+ constexpr static bool value = std::is_same_v;
+ };
+
+ template
+ struct is_forward_iterator_category
+ {
+ constexpr static bool value = std::is_same_v;
+ };
+
+ template
+ struct is_bidirectional_iterator_category
+ {
+ constexpr static bool value = std::is_same_v;
+ };
+
+ template
+ struct is_random_access_iterator_category
+ {
+ constexpr static bool value = std::is_same_v;
+ };
+
+ template
+ inline constexpr bool is_input_iterator_category_v = is_input_iterator_category::value;
+
+ template
+ inline constexpr bool is_forward_iterator_category_v = is_forward_iterator_category::value;
+
+ template
+ inline constexpr bool is_bidirectional_iterator_category_v = is_bidirectional_iterator_category::value;
+
+ template
+ inline constexpr bool is_random_access_iterator_category_v = is_random_access_iterator_category::value;
+
+ template
+ inline constexpr bool is_bidirectional_or_better_category_v =
+ is_bidirectional_iterator_category_v || is_random_access_iterator_category_v;
+
// this is required! :/
template
- struct is_input_iterator {
- constexpr static bool value = std::is_same_v::iterator_category, std::input_iterator_tag>;
+ struct is_input_iterator
+ {
+ constexpr static bool value = is_input_iterator_category_v::iterator_category>;
};
template
- struct is_forward_iterator {
- constexpr static bool value = std::is_same_v::iterator_category, std::forward_iterator_tag>;
+ struct is_forward_iterator
+ {
+ constexpr static bool value = is_forward_iterator_category_v::iterator_category>;
};
template
- struct is_bidirectional_iterator {
- constexpr static bool value = std::is_same_v::iterator_category, std::bidirectional_iterator_tag>;
+ struct is_bidirectional_iterator
+ {
+ constexpr static bool value = is_bidirectional_iterator_category_v::iterator_category>;
};
template
- struct is_random_access_iterator {
- constexpr static bool value = std::is_same_v::iterator_category, std::random_access_iterator_tag>;
+ struct is_random_access_iterator
+ {
+ constexpr static bool value = is_random_access_iterator_category_v::iterator_category>;
};
template
@@ -61,6 +105,27 @@ namespace blt::meta
template
inline constexpr bool is_bidirectional_or_better_v = is_bidirectional_iterator_v || is_random_access_iterator_v;
+
+ template
+ struct lowest_iterator_category
+ {
+ using type = std::common_type_t::iterator_category...>;
+ };
+
+ template
+ using lowest_iterator_category_t = typename lowest_iterator_category::type;
+
+ template
+ struct is_reverse_iterator : std::false_type
+ {
+ };
+
+ template
+ struct is_reverse_iterator> : std::true_type
+ {};
+
+ template
+ inline constexpr bool is_reverse_iterator_v = is_reverse_iterator::value;
}
#endif //BLT_META_ITERATOR_H
diff --git a/include/blt/std/allocator.h b/include/blt/std/allocator.h
index 91e7e5d..873c0e4 100644
--- a/include/blt/std/allocator.h
+++ b/include/blt/std/allocator.h
@@ -22,7 +22,7 @@
#include
#include
#include
- #include
+ #include
#include
#include
#include
@@ -159,10 +159,10 @@ namespace blt
*/
inline std::optional 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)
- return block_view{blk, kv.first, kv.second.n - n};
+ if (item.n >= n)
+ return block_view{blk, index, item.n - n};
}
return {};
}
diff --git a/include/blt/std/iterator.h b/include/blt/std/iterator.h
deleted file mode 100644
index c1f0119..0000000
--- a/include/blt/std/iterator.h
+++ /dev/null
@@ -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 .
- */
-
-#ifndef BLT_ITERATOR_H
-#define BLT_ITERATOR_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-namespace blt
-{
-
- // forward declare useful types
- template>
- class enumerator;
-
- template>
- class enumerator_rev;
-
- namespace iterator
- {
- template>
- class enumerate_wrapper;
-
- /**
- * struct which is returned by the enumerator.
- * @tparam T type to store.
- */
- template
- 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
- 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
- class enumerate_iterator_base : public pair_iterator_base
- {
- public:
- explicit enumerate_iterator_base(Iter iter, blt::size_t place = 0):
- pair_iterator_base(std::move(iter), place)
- {}
-
- enumerate_item> 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
- class enumerate_forward_iterator : public enumerate_iterator_base
- {
- public:
- using enumerate_iterator_base::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
- class enumerate_bidirectional_iterator : public enumerate_forward_iterator
- {
- public:
- using enumerate_forward_iterator::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
- class enumerate_wrapper, std::void_t>>
- : public enumerate_forward_iterator
- {
- public:
- using iterator_category = std::forward_iterator_tag;
- using value_type = enumerate_item>;
- using difference_type = typename std::iterator_traits::difference_type;
- using pointer = value_type;
- using reference = value_type;
- using iterator_type = Iter;
-
- using enumerate_forward_iterator::enumerate_forward_iterator;
- };
-
- /**
- * Wrapper class for bidirectional iterators or random access iterators.
- * @tparam Iter iterator type.
- */
- template
- class enumerate_wrapper, std::void_t>>
- : public enumerate_bidirectional_iterator
- {
- public:
- using iterator_category = typename std::iterator_traits::iterator_category;
- using value_type = enumerate_item>;
- using difference_type = typename std::iterator_traits::difference_type;
- using pointer = value_type;
- using reference = value_type;
- using iterator_type = Iter;
-
- using enumerate_bidirectional_iterator::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
- 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{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{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
- class enumerator_reversible : public enumerator_base
- {
- public:
- explicit enumerator_reversible(Iter begin, Iter end, blt::size_t container_size):
- enumerator_base{IterWrapper{enumerate_wrapper{std::move(begin), 0}},
- IterWrapper{enumerate_wrapper{std::move(end), container_size}}}
- {}
-
- explicit enumerator_reversible(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
- enumerator_base(IterWrapper{enumerate_wrapper{std::move(begin), begin_index}},
- IterWrapper{enumerate_wrapper{std::move(end), end_index}})
- {}
-
- /**
- * Reverses the enumerator’s direction.
- */
- auto rev() const
- {
- return enumerator_rev{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
- class enumerator_random_access : public enumerator_reversible
- {
- public:
- using enumerator_reversible::enumerator_reversible;
-
- auto skip(blt::size_t amount)
- {
- return enumerator{this->begin_.base() + amount,
- this->end_.base(),
- this->begin_.get_index() + amount,
- this->end_.get_index()};
- }
-
- auto take(blt::size_t amount)
- {
- return enumerator{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).
- */
- template