Merge remote-tracking branch 'refs/remotes/origin/main'
commit
bfcb357059
|
@ -1,4 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakePythonSetting">
|
||||
<option name="pythonIntegrationState" value="YES" />
|
||||
</component>
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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,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 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 ()
|
||||
|
|
260
commit.py
260
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])
|
||||
|
||||
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)? ")
|
||||
|
||||
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()
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include <blt/std/types.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/iterator/iter_common.h>
|
||||
#include <blt/iterator/common.h>
|
||||
#include <blt/iterator/zip.h>
|
||||
#include <blt/meta/meta.h>
|
||||
#include <blt/meta/iterator.h>
|
||||
|
@ -59,118 +59,6 @@ namespace blt
|
|||
template<typename Iter1, typename Iter2, typename = std::void_t<>>
|
||||
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.
|
||||
* @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()))};
|
||||
}
|
||||
};
|
||||
|
||||
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...>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,12 +19,158 @@
|
|||
#ifndef 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>
|
||||
|
||||
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
|
||||
|
|
|
@ -24,27 +24,71 @@
|
|||
|
||||
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! :/
|
||||
|
||||
|
||||
template<typename Iter>
|
||||
struct is_input_iterator {
|
||||
constexpr static bool value = std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::input_iterator_tag>;
|
||||
struct is_input_iterator
|
||||
{
|
||||
constexpr static bool value = is_input_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
|
||||
};
|
||||
|
||||
template<typename Iter>
|
||||
struct is_forward_iterator {
|
||||
constexpr static bool value = std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::forward_iterator_tag>;
|
||||
struct is_forward_iterator
|
||||
{
|
||||
constexpr static bool value = is_forward_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
|
||||
};
|
||||
|
||||
template<typename Iter>
|
||||
struct is_bidirectional_iterator {
|
||||
constexpr static bool value = std::is_same_v<typename std::iterator_traits<Iter>::iterator_category, std::bidirectional_iterator_tag>;
|
||||
struct is_bidirectional_iterator
|
||||
{
|
||||
constexpr static bool value = is_bidirectional_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
|
||||
};
|
||||
|
||||
template<typename Iter>
|
||||
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>;
|
||||
struct is_random_access_iterator
|
||||
{
|
||||
constexpr static bool value = is_random_access_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
|
||||
};
|
||||
|
||||
template<typename Iter>
|
||||
|
@ -61,6 +105,27 @@ namespace blt::meta
|
|||
|
||||
template<typename 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
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include <limits>
|
||||
#include <vector>
|
||||
#include <blt/std/ranges.h>
|
||||
#include <blt/std/iterator.h>
|
||||
#include <blt/iterator/iterator.h>
|
||||
#include <blt/std/utility.h>
|
||||
#include <blt/std/types.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)
|
||||
{
|
||||
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 {};
|
||||
}
|
||||
|
|
|
@ -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 enumerator’s 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
|
|
@ -174,6 +174,12 @@ namespace blt::random
|
|||
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()
|
||||
{
|
||||
return BLT_RANDOM_DOUBLE(seed) < 0.5;
|
||||
|
|
|
@ -134,35 +134,35 @@ namespace blt
|
|||
iterator<C1_ITER, C2_ITER> end_;
|
||||
};
|
||||
|
||||
template<typename T, typename G>
|
||||
static inline auto in_pairs(const T& container1, const G& container2)
|
||||
{
|
||||
return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
|
||||
}
|
||||
|
||||
template<typename T, typename G>
|
||||
static inline auto in_pairs(T& container1, G& container2)
|
||||
{
|
||||
return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
|
||||
}
|
||||
|
||||
template<typename T, typename G, blt::size_t 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]};
|
||||
}
|
||||
|
||||
template<typename T, typename G, blt::size_t size>
|
||||
static inline auto in_pairs(T(& container1)[size], G(& container2)[size])
|
||||
{
|
||||
return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]};
|
||||
}
|
||||
|
||||
template<typename T, typename G>
|
||||
static inline auto in_pairs(T&& container1, G&& container2)
|
||||
{
|
||||
return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
|
||||
}
|
||||
// template<typename T, typename G>
|
||||
// static inline auto in_pairs(const T& container1, const G& container2)
|
||||
// {
|
||||
// return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
|
||||
// }
|
||||
//
|
||||
// template<typename T, typename G>
|
||||
// static inline auto in_pairs(T& container1, G& container2)
|
||||
// {
|
||||
// return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
|
||||
// }
|
||||
//
|
||||
// template<typename T, typename G, blt::size_t 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]};
|
||||
// }
|
||||
//
|
||||
// template<typename T, typename G, blt::size_t size>
|
||||
// static inline auto in_pairs(T(& container1)[size], G(& container2)[size])
|
||||
// {
|
||||
// return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]};
|
||||
// }
|
||||
//
|
||||
// template<typename T, typename G>
|
||||
// static inline auto in_pairs(T&& container1, G&& container2)
|
||||
// {
|
||||
// return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
|
||||
// }
|
||||
|
||||
template<typename T>
|
||||
struct range
|
||||
|
|
|
@ -42,8 +42,8 @@ namespace blt
|
|||
using pointer = T*;
|
||||
using const_reference = const T&;
|
||||
using const_pointer = const T*;
|
||||
using iterator = blt::ptr_iterator<T>;
|
||||
using const_iterator = blt::ptr_iterator<const T>;
|
||||
using iterator = T*;
|
||||
using const_iterator = const T*;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
public:
|
||||
|
@ -131,24 +131,24 @@ namespace blt
|
|||
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()
|
||||
{
|
||||
return buffer_;
|
||||
return buffer_.data();
|
||||
}
|
||||
|
||||
constexpr inline const_pointer data() const
|
||||
{
|
||||
return buffer_;
|
||||
return buffer_.data();
|
||||
}
|
||||
|
||||
constexpr inline reference front()
|
||||
|
@ -290,8 +290,8 @@ namespace blt
|
|||
using const_reference = const value_type&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = const pointer;
|
||||
using iterator = blt::ptr_iterator<T>;
|
||||
using const_iterator = blt::ptr_iterator<const T>;
|
||||
using iterator = T*;
|
||||
using const_iterator = const T*;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include <blt/parse/argparse.h>
|
||||
#include <iostream>
|
||||
#include <blt/std/string.h>
|
||||
#include <blt/std/iterator.h>
|
||||
#include <blt/iterator/iterator.h>
|
||||
#include <algorithm>
|
||||
#include "blt/std/utility.h"
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <blt/parse/obj_loader.h>
|
||||
#include <blt/fs/loader.h>
|
||||
#include <blt/std/string.h>
|
||||
#include <blt/std/iterator.h>
|
||||
#include <blt/iterator/iterator.h>
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include "blt/std/assert.h"
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -28,8 +28,8 @@ namespace blt::test
|
|||
void print(const T& ref)
|
||||
{
|
||||
BLT_TRACE_STREAM << "(" << ref.size() << ") [";
|
||||
for (auto v : blt::enumerate(ref))
|
||||
BLT_TRACE_STREAM << v.second << ((v.first != ref.size()-1) ? ", " : "]\n");
|
||||
for (auto [index, item] : blt::enumerate(ref))
|
||||
BLT_TRACE_STREAM << item << ((index != ref.size()-1) ? ", " : "]\n");
|
||||
}
|
||||
|
||||
void vector_run()
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <blt/fs/nbt.h>
|
||||
#include <blt/profiling/profiler.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/std/format.h>
|
||||
#include <blt/format/format.h>
|
||||
#include <blt/fs/filesystem.h>
|
||||
#include <filesystem>
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace blt::tests {
|
|||
template<typename T>
|
||||
T* generateRandomData(T* arr, size_t size, uint32_t seed = 0) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "blt/profiling/profiler_v2.h"
|
||||
#include "blt/std/logging.h"
|
||||
#include "blt/std/time.h"
|
||||
#include "blt/std/format.h"
|
||||
#include "blt/format/format.h"
|
||||
|
||||
void print(const std::vector<std::string>& vtr) {
|
||||
for (const auto& line : vtr)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <blt/std/utility.h>
|
||||
#include <blt/std/string.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/iterator/iterator.h>
|
||||
|
||||
namespace blt::test
|
||||
{
|
||||
|
@ -32,27 +33,27 @@ namespace blt::test
|
|||
auto sv_splits_c = blt::string::split_sv(str, ' ');
|
||||
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
|
||||
{
|
||||
BLT_DEBUG(v.second);
|
||||
BLT_DEBUG(item);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
BLT_DEBUG(v.second);
|
||||
BLT_DEBUG(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <blt/std/utility.h>
|
||||
#include <blt/std/format.h>
|
||||
#include <blt/format/format.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/profiling/profiler_v2.h>
|
||||
#include <utility_test.h>
|
||||
|
|
Loading…
Reference in New Issue