Add pwn challenges

This commit is contained in:
agatha 2023-11-24 13:11:34 -05:00
parent 9fc78dc013
commit 55a9ec93f2
306 changed files with 36633 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,16 @@
FROM debian:bookworm-slim@sha256:ea5ad531efe1ac11ff69395d032909baf423b8b88e9aade07e11b40b2e5a1338
EXPOSE 1337
RUN DEBIAN_FRONTEND=noninteractive; \
apt -y update; \
apt -y install socat
WORKDIR /app
COPY chall/chall app
COPY chall/flag.txt flag.txt
CMD socat -T 60 \
TCP-LISTEN:1337,nodelay,reuseaddr,fork \
EXEC:"stdbuf -i0 -o0 -e0 /app/app",stderr

View File

@ -0,0 +1,8 @@
build: wasm_host/src/main.rs
cd wasm_host && cargo build --release && cd ..
cp wasm_host/target/release/wasm_host chall
debug: wasm_host/src/main.rs
cd wasm_host && cargo build && cd ..
all: build

Binary file not shown.

View File

@ -0,0 +1 @@
gctf{NotTheFlag}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
[package]
name = "wasm_host"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.75"
base64 = "0.21.5"
wasmtime = "=6.0.0"
wasmtime-wasi = "=6.0.0"
cranelift-codegen = "=0.93.0"
cranelift-codegen-meta = "=0.93.0"
cranelift-codegen-shared = "=0.93.0"

View File

@ -0,0 +1,55 @@
use anyhow::anyhow;
use base64::{engine::general_purpose as base64_engine, Engine as _};
use wasmtime::*;
use wasmtime_wasi::sync::WasiCtxBuilder;
fn main() -> anyhow::Result<()> {
let mut config = Config::new();
config.debug_info(false);
config.cranelift_debug_verifier(false);
config.strategy(Strategy::Cranelift);
config.cranelift_opt_level(OptLevel::SpeedAndSize);
config.static_memory_forced(true);
let engine = Engine::new(&config)?;
let mut linker = Linker::new(&engine);
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
let wasi = WasiCtxBuilder::new().inherit_stdio().build();
let mut store = Store::new(&engine, wasi);
println!("Enter your module in base64:");
let user_module_wat = {
let stdin = std::io::stdin();
let mut user_module_wat = String::new();
stdin.read_line(&mut user_module_wat)?;
let user_module_wat = user_module_wat
.strip_suffix("\n")
.unwrap_or(&user_module_wat);
match base64_engine::STANDARD.decode(&user_module_wat) {
Ok(user_module_wat) => user_module_wat,
Err(_) => return Err(anyhow!("invalid base64")),
}
};
let user_module = match Module::new(&engine, user_module_wat) {
Ok(user_module) => user_module,
Err(_) => return Err(anyhow!("invalid module")),
};
let _ = linker.module(&mut store, "module", &user_module)?;
linker
.get_default(&mut store, "module")?
.typed::<(), ()>(&store)?
.call(&mut store, ())?;
Ok(())
}

View File

@ -0,0 +1,20 @@
# Read the comments, they are actually helpful. (like this one)
version: "3"
services:
app:
# Challenge related options
build: .
ports:
- 1337:1337
# Uncomment this block during development
# Every time you rebuild your file you can immeditately test it
# volumes:
# - ./chall:/app
# Security releated options
user: 1337:1337
privileged: false
read_only: true
cap_add: [] # See "man 7 capabilities" for a full list
cap_drop: [] # See "man 7 capabilities" for a full list

View File

@ -0,0 +1,8 @@
wasi-sdk=/opt/wasi-sdk
payload: payload.c
$(wasi-sdk)/bin/clang payload.c --target=wasm32-unknown-wasi --sysroot $(wasi-sdk)/share/wasi-sysroot/ \
-O0 -g -o payload.wasm
base64 payload.wasm -w 0 > payload.wasm.base64
all: payload

View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main(int argc, char ** argv) {
printf("Hello Wasi\n");
}

View File

@ -0,0 +1,5 @@
# Example
This example uses [wasi-sdk](https://github.com/WebAssembly/wasi-sdk).
You have to install it and then you might need to modify the wasi-sdk variable in the Makefile.
Of course this challenge can be solved in any language that has a wasm+wasi target.

View File

@ -0,0 +1,7 @@
My friend hosts this wasm runtime that uses an outdated version of wasmtime. We pwned it and left a flag there. Can you get it?
author: PaideiaDilemma
```
nc chall.glacierctf.com 13389
```

8
pwn/flipper/README.md Normal file
View File

@ -0,0 +1,8 @@
Our OS professor keeps talking about Rowhammer, and how dangerous it is. I don't believe him, so you even get 3 bitflips to try and steal the flag from my kernel!
Base repo is https://github.com/IAIK/sweb (commit ad1b59a5c2acbd4bff346bdf282a4d5e21bd9cb1) Build instructions at here
author: hweissi
```
nc chall.glacierctf.com 13371
```

BIN
pwn/flipper/chall.zip Normal file

Binary file not shown.

173
pwn/flipper/challenge.diff Normal file
View File

@ -0,0 +1,173 @@
diff --git a/common/include/kernel/Scheduler.h b/common/include/kernel/Scheduler.h
index c8fa74bf..dd7a9b45 100644
--- a/common/include/kernel/Scheduler.h
+++ b/common/include/kernel/Scheduler.h
@@ -26,7 +26,6 @@ class Scheduler
bool isCurrentlyCleaningUp();
void incTicks();
size_t getTicks();
-
/**
* NEVER EVER EVER CALL THIS METHOD OUTSIDE OF AN INTERRUPT CONTEXT
* this is the method that decides which threads will be scheduled next
@@ -34,6 +33,7 @@ class Scheduler
* and changes the global variables currentThread and currentThreadRegisters
*/
void schedule();
+ int flipped_already; // Here to have it in a singleton
protected:
friend class IdleThread;
diff --git a/common/include/kernel/Syscall.h b/common/include/kernel/Syscall.h
index 8088db19..f0656a69 100644
--- a/common/include/kernel/Syscall.h
+++ b/common/include/kernel/Syscall.h
@@ -15,7 +15,7 @@ class Syscall
static size_t close(size_t fd);
static size_t open(size_t path, size_t flags);
static void pseudols(const char *pathname, char *buffer, size_t size);
-
+ static int flipBit(char* address, int bitnum);
static size_t createprocess(size_t path, size_t sleep);
static void trace();
};
diff --git a/common/include/kernel/syscall-definitions.h b/common/include/kernel/syscall-definitions.h
index dd99d197..88525f9b 100644
--- a/common/include/kernel/syscall-definitions.h
+++ b/common/include/kernel/syscall-definitions.h
@@ -17,3 +17,5 @@
#define sc_createprocess 191
#define sc_trace 252
+#define sc_flip_bit 69
+
diff --git a/common/include/kernel/user_progs.h b/common/include/kernel/user_progs.h
index 65617274..79e5b2a2 100644
--- a/common/include/kernel/user_progs.h
+++ b/common/include/kernel/user_progs.h
@@ -3,7 +3,7 @@
// DO NOT CHANGE THE NAME OR THE TYPE OF THE user_progs VARIABLE!
char const *user_progs[] = {
// for reasons of automated testing
- "/usr/shell.sweb",
+ "/usr/exploit.sweb",
0
};
diff --git a/common/source/kernel/Scheduler.cpp b/common/source/kernel/Scheduler.cpp
index 31ef1da9..2148b991 100644
--- a/common/source/kernel/Scheduler.cpp
+++ b/common/source/kernel/Scheduler.cpp
@@ -28,6 +28,7 @@ Scheduler *Scheduler::instance()
Scheduler::Scheduler()
{
+ flipped_already = 0;
block_scheduling_ = 0;
ticks_ = 0;
addNewThread(&cleanup_thread_);
diff --git a/common/source/kernel/Syscall.cpp b/common/source/kernel/Syscall.cpp
index 964cd5b4..9c161cad 100644
--- a/common/source/kernel/Syscall.cpp
+++ b/common/source/kernel/Syscall.cpp
@@ -7,6 +7,9 @@
#include "ProcessRegistry.h"
#include "File.h"
#include "Scheduler.h"
+#include "ArchMemory.h"
+#include "Loader.h"
+
size_t Syscall::syscallException(size_t syscall_number, size_t arg1, size_t arg2, size_t arg3, size_t arg4, size_t arg5)
{
@@ -49,6 +52,10 @@ size_t Syscall::syscallException(size_t syscall_number, size_t arg1, size_t arg2
case sc_pseudols:
pseudols((const char*) arg1, (char*) arg2, arg3);
break;
+ case sc_flip_bit:
+ return_value = flipBit((char*) arg1, (int) arg2);
+ break;
+
default:
return_value = -1;
kprintf("Syscall::syscallException: Unimplemented Syscall Number %zd\n", syscall_number);
@@ -56,6 +63,24 @@ size_t Syscall::syscallException(size_t syscall_number, size_t arg1, size_t arg2
return return_value;
}
+int Syscall::flipBit(char* address, int bitnum)
+{
+
+ if(bitnum > 7 || bitnum < 0)
+ {
+ return -1;
+ }
+ if(Scheduler::instance()->flipped_already != 0)
+ {
+ return -2;
+ }
+ Scheduler::instance()->flipped_already = 0xfff;
+ char mask = (1 << bitnum);
+ *address ^= mask;
+
+ return 0;
+}
+
void Syscall::pseudols(const char *pathname, char *buffer, size_t size)
{
if(buffer && ((size_t)buffer >= USER_BREAK || (size_t)buffer + size > USER_BREAK))
diff --git a/common/source/kernel/main.cpp b/common/source/kernel/main.cpp
index f7957074..c51fef8b 100644
--- a/common/source/kernel/main.cpp
+++ b/common/source/kernel/main.cpp
@@ -28,6 +28,8 @@
extern void* kernel_end_address;
+const char* flag = "gctf{TEST_FLAG_NOT_REAL_HF}";
+
uint8 boot_stack[0x4000] __attribute__((aligned(0x4000)));
SystemState system_state;
FileSystemInfo* default_working_dir;
diff --git a/userspace/libc/include/nonstd.h b/userspace/libc/include/nonstd.h
index 3f341b55..cc5dd694 100644
--- a/userspace/libc/include/nonstd.h
+++ b/userspace/libc/include/nonstd.h
@@ -15,7 +15,7 @@ extern "C" {
*
*/
extern int createprocess(const char* path, int sleep);
-
+extern int flipBit(const void* address, int bit_num);
#ifdef __cplusplus
}
#endif
diff --git a/userspace/libc/src/nonstd.c b/userspace/libc/src/nonstd.c
index b9ec3d11..043a2466 100644
--- a/userspace/libc/src/nonstd.c
+++ b/userspace/libc/src/nonstd.c
@@ -8,6 +8,12 @@ int createprocess(const char* path, int sleep)
return __syscall(sc_createprocess, (long) path, sleep, 0x00, 0x00, 0x00);
}
+int flipBit(const void* address, int bit_num)
+{
+ return __syscall(sc_flip_bit, (long) address, bit_num, 0, 0, 0);
+}
+
+
extern int main();
void _start()
diff --git a/utils/images/menu.lst b/utils/images/menu.lst
index cf7fd93d..f230876e 100644
--- a/utils/images/menu.lst
+++ b/utils/images/menu.lst
@@ -1,6 +1,6 @@
default 0
-
+timeout=0
title = Sweb
root (hd0,0)
kernel = /boot/kernel.x

255
pwn/flipper/dist/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,255 @@
cmake_minimum_required(VERSION 3.5)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
# Include custom CMake modules from the cmake/ subdirectory
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
set(HDD_IMAGE_RAW "SWEB-flat.vmdk")
set(HDD_IMAGE "SWEB.qcow2")
set (ARCH "x86/64")
MESSAGE("-- Target architecture: ${ARCH}")
unset(CMAKE_CROSSCOMPILING)
if(APPLE OR WIN32)
set(CMAKE_CROSSCOMPILING 1)
MESSAGE("-- Cross-Compiling on Apple/Windows")
endif(APPLE OR WIN32)
# add-dbg for userspace binaries
include(AddDebugInfo)
# include(arch/${ARCH}/CMakeLists.compiler)
project(sweb
LANGUAGES C CXX ASM)
string(REPLACE "/" ";" ARCH_LIST ${ARCH})
string(REPLACE "/" "_" ARCH_ESC ${ARCH})
string(TOUPPER ${ARCH_ESC} ARCH_ESC)
add_definitions(-DCMAKE_${ARCH_ESC}=1)
list(LENGTH ARCH_LIST ARCH_DEPTH)
#Find program executables needed during compilation
find_program(LD_EXECUTABLE gcc)
find_program(OBJCOPY_EXECUTABLE objcopy)
find_program(DOXYGEN_EXECUTABLE doxygen)
find_program(STAT_EXECUTABLE stat)
set(ColourReset "")
set(BoldRed "")
if(NOT WIN32)
string(ASCII 27 Esc)
set(ColourReset "${Esc}[m")
set(BoldRed "${Esc}[1;31m")
endif()
# set(TMPFS_CHECK "none")
# execute_process(COMMAND ${STAT_EXECUTABLE} --file-system --format=%T ${PROJECT_BINARY_DIR}
# OUTPUT_VARIABLE TMPFS_CHECK
# OUTPUT_STRIP_TRAILING_WHITESPACE)
# if(NOT("${TMPFS_CHECK}" STREQUAL "tmpfs"))
# MESSAGE("-- ${BoldRed}WARNING: build folder is not tmpfs - compilation will be slow and bad for the hard disk${ColourReset}")
# endif(NOT("${TMPFS_CHECK}" STREQUAL "tmpfs"))
set(NOPIEFLAG -no-pie)
execute_process(COMMAND ${LD_EXECUTABLE} ${NOPIEFLAG}
ERROR_VARIABLE PIE_CHECK
ERROR_STRIP_TRAILING_WHITESPACE)
if("${PIE_CHECK}" MATCHES ".*unrecognized.*")
set(NOPIEFLAG )
endif()
set(NOPICFLAG -fno-PIC)
execute_process(COMMAND ${CMAKE_C_COMPILER} ${NOPICFLAG}
ERROR_VARIABLE PIC_CHECK
ERROR_STRIP_TRAILING_WHITESPACE)
if("${PIC_CHECK}" MATCHES ".*unrecognized.*")
set(NOPICFLAG )
endif()
#Initialize CMake output directories
set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib")
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}")
include(arch/${ARCH}/CMakeLists.include)
include(arch/${ARCH}/CMakeLists.userspace)
string (REPLACE ";" " " KERNEL_CMAKE_C_FLAGS_STR "${KERNEL_CMAKE_C_FLAGS}")
set(CMAKE_ASM_FLAGS ${KERNEL_CMAKE_C_FLAGS_STR})
if(CMAKE_CROSSCOMPILING)
set(CMAKE_CROSS_COMPILE_FLAGS -G "Unix Makefiles")
else(CMAKE_CROSSCOMPILING) # not cross compiling
set(CMAKE_CROSS_COMPILE_FLAGS )
endif(CMAKE_CROSSCOMPILING)
# if ("${DEBUG}" STREQUAL "1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG=1")
# endif()
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/kernel.x
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/kernel64.x
DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
# Searches for asm, c and cpp files and adds the library
function(ADD_PROJECT_LIBRARY LIBRARY_NAME)
arch2obj(archobj_libname ${LIBRARY_NAME})
file(GLOB source_files ${SOURCE_WILDCARDS})
set(library_files)
if(source_files)
set(library_files ${source_files})
endif(source_files)
if(archobj_libname)
set(library_files ${library_files} $<TARGET_OBJECTS:${archobj_libname}>)
endif(archobj_libname)
if(library_files)
add_library(${LIBRARY_NAME} ${library_files})
if(archobj_libname)
add_dependencies(${LIBRARY_NAME} ${archobj_libname})
endif(archobj_libname)
target_compile_options(${LIBRARY_NAME} PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${KERNEL_CMAKE_CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:C>:${KERNEL_CMAKE_C_FLAGS}>
)
set(ENV{LIBRARY_NAMES} "$ENV{LIBRARY_NAMES};${LIBRARY_NAME}")
endif(library_files)
endfunction(ADD_PROJECT_LIBRARY)
set (SOURCE_WILDCARDS *.cpp *.c *.S)
set(LIBRARY_FILENAMES)
#Initialize global (environment) variables
set(ENV{LIBRARY_NAMES})
#Create target for userspace libc (Need to to that here because some files (e.g. syscall.c) are all over the place)
add_library(userspace_libc "")
target_compile_options(userspace_libc PUBLIC ${ARCH_USERSPACE_COMPILE_OPTIONS})
#Add the source directories
add_subdirectory(arch)
# add_subdirectory(common)
add_subdirectory(utils)
add_subdirectory(userspace)
#FINAL_LIB_NAMES should contain the names of all libraries
#these names can be used to link the kernel, no unpacking of *.a files is needed anymore
set(FINAL_LIB_NAMES $ENV{LIBRARY_NAMES})
#Name of the executables of the userspace, needed for dependency checking
set(FINAL_USERSPACE_NAMES $ENV{USERSPACE_NAMES})
#Build the Linker command
set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -g -u entry -Wl,-T ${CMAKE_SOURCE_DIR}/arch/${ARCH}/utils/kernel-ld-script.ld)
set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -o ${PROJECT_BINARY_DIR}/kernel.x)
#set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -Wl,-Map -Wl,${PROJECT_BINARY_DIR}/kernel.map)
set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -Wl,--start-group)
foreach(libfile ${FINAL_LIB_NAMES})
set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} ${LIBRARY_OUTPUT_PATH}/lib${libfile}.a)
endforeach(libfile)
set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} -Wl,--end-group)
set(KERNEL_LD_ARGUMENT ${KERNEL_LD_ARGUMENT} ${ARCH_APPEND_LD_ARGUMENTS})
#Build userspace exe2minixfs command
set(MINIXFS_ARGUMENT "")
foreach(file $ENV{USERSPACE_NAMES_EXE2MINIX})
list(APPEND MINIXFS_ARGUMENT ${file})
endforeach(file)
file(GLOB userspace_data userspace/data/*)
foreach(file ${userspace_data})
get_filename_component(datafile ${file} NAME)
list(APPEND MINIXFS_ARGUMENT ${file} ${datafile})
endforeach(file)
#Custom Target: hdd_image
#Creates the hd image and copies all files to it
add_custom_target (hdd_image ALL
DEPENDS kernel_to_image userspace_to_image
COMMAND qemu-img convert -f raw -O qcow2 ${HDD_IMAGE_RAW} ${HDD_IMAGE}
)
#Custom Command: invoke exe2minixfs and copy boot files to our hd image
add_custom_target (kernel_to_image
DEPENDS blank_hdd_image exe2minixfs
# x86/32 doesn't generate kernel.dbg
COMMAND ${CMAKE_COMMAND} -E touch "./kernel.dbg"
COMMAND ./exe2minixfs ${HDD_IMAGE_RAW} 32256 "${CMAKE_SOURCE_DIR}/utils/images/menu.lst" boot/grub/menu.lst
./kernel.x boot/kernel.x
./kernel.dbg boot/kernel.dbg
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Copying kernel files to image..."
)
#Custom Command: invoke exe2minixfs and copy all userspace programs to our hd image second partition
add_custom_target (userspace_to_image
DEPENDS blank_hdd_image ${FINAL_USERSPACE_NAMES} exe2minixfs
COMMAND mkdir -p userspace/data
COMMAND cp -f ${CMAKE_SOURCE_DIR}/userspace/data/* ${PROJECT_BINARY_DIR}/userspace/data
COMMAND ./exe2minixfs ${HDD_IMAGE_RAW} 10321920 ${MINIXFS_ARGUMENT}
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMENT "Copying userspace programs to image..."
)
#Custom target: make bochs
#Run bochs in non debugging mode
add_custom_target(bochs
COMMAND ${BOCHS_PATH} -q -f ${PROJECT_SOURCE_DIR}/utils/bochsrc
COMMENT "Going to ${BOCHS_PATH} -f ${PROJECT_SOURCE_DIR}/utils/bochsrc"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
#Custom target: make bochsgdb
#Run bochs in debugging mode
add_custom_target(bochsgdb
COMMAND ${BOCHS_PATH} -q -f '${PROJECT_SOURCE_DIR}/utils/bochsrc' "gdbstub: enabled=1, port=1234"
COMMENT "Going to ${BOCHS_PATH} -f ${PROJECT_SOURCE_DIR}/utils/bochsrc \"gdbstub: enabled=1, port=1234\""
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
)
#Custom target: make emu
#Run qemu in emu mode
add_custom_target(emu
COMMAND cat '${PROJECT_SOURCE_DIR}/utils/emu.txt'
)
# Define the "make ${ARCH}" targets
include(MakeArchTarget)
MAKE_ARCH_TARGET(x86_32 x86/32 "")
MAKE_ARCH_TARGET(x86_32_pae x86/32/pae "")
MAKE_ARCH_TARGET(x86_64 x86/64 "")
MAKE_ARCH_TARGET(arm_icp arm/integratorcp "")
MAKE_ARCH_TARGET(arm_rpi2 arm/rpi2 "")
MAKE_ARCH_TARGET(armv8_rpi3 armv8/rpi3 "-DVIRTUALIZED_QEMU=1")
MAKE_ARCH_TARGET(armv8_rpi3_hardware armv8/rpi3 "")

6
pwn/flipper/dist/README.md vendored Normal file
View File

@ -0,0 +1,6 @@
# Notes
This is a setup to run a fixed kernel with new userspace.
Please read the instructions [here](https://www.iaik.tugraz.at/teaching/materials/os/tutorials/prerequisites-installation/) to find out how to compile and run.
The same instructions also work for the source code at https://github.com/iaik/sweb, which is probably easier for debugging.

4
pwn/flipper/dist/arch/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,4 @@
include(${ARCH}/CMakeLists.subfolders)

0
pwn/flipper/dist/arch/x86/64/.keep vendored Normal file
View File

View File

@ -0,0 +1,14 @@
if(CMAKE_CROSSCOMPILING)
INCLUDE(CMakeForceCompiler)
SET(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
find_program(CMAKE_ASM_COMPILER x86_64-linux-gnu-gcc)
find_program(CMAKE_C_COMPILER x86_64-linux-gnu-gcc)
find_program(CMAKE_CXX_COMPILER x86_64-linux-gnu-g++)
find_program(LD_EXECUTABLE x86_64-linux-gnu-gcc)
find_program(OBJCOPY_EXECUTABLE x86_64-linux-gnu-objcopy)
endif(CMAKE_CROSSCOMPILING)

View File

@ -0,0 +1,67 @@
set(KERNEL_BINARY kernel64.x)
if (CMAKE_COMPILER_IS_GNUCC AND (CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 8 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8))
set(FCF_PROTECTION_FLAG -fcf-protection=none)
else()
set(FCF_PROTECTION_FLAG )
endif()
set(ARCH_X86_64_KERNEL_CFLAGS -m64 -O0 -gdwarf-2 -Wall -Wextra -Werror -Wno-error=format -Wno-nonnull-compare -nostdinc -nostdlib -nostartfiles -nodefaultlibs -fno-builtin -fno-exceptions -fno-stack-protector -ffreestanding -mcmodel=kernel -mno-red-zone -mgeneral-regs-only -mno-mmx -mno-sse2 -mno-sse3 -mno-3dnow ${FCF_PROTECTION_FLAG} ${NOPICFLAG})
set(KERNEL_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -std=gnu++17 -nostdinc++ -fno-rtti ${ARCH_X86_64_KERNEL_CFLAGS})
set(KERNEL_CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -std=gnu11 ${ARCH_X86_64_KERNEL_CFLAGS})
set(ARCH_LD_ARGUMENTS -m64 -Wl,--build-id=none -Wl,-z,max-page-size=0x1000 -Wl,-melf_x86_64 -nostdinc -nostdlib -nodefaultlibs)
set(KERNEL_LD_ARGUMENT ${ARCH_LD_ARGUMENTS} -mcmodel=kernel ${NOPIEFLAG})
set(ARCH_APPEND_LD_ARGUMENTS )
function(ARCH2OBJ ARCHOBJ_LIBNAME LIBRARY_NAME)
file(GLOB arch_files "*.32.C")
if(arch_files)
set(ARCHOBJS_TARGET ${LIBRARY_NAME}_archobjs)
add_library(${ARCHOBJS_TARGET} OBJECT ${arch_files})
target_compile_options(${ARCHOBJS_TARGET} PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:${KERNEL_CMAKE_CXX_FLAGS}>
$<$<COMPILE_LANGUAGE:C>:${KERNEL_CMAKE_C_FLAGS}>
-m32 -g0 -mcmodel=32 -mgeneral-regs-only -momit-leaf-frame-pointer -Wa,--64 -fno-toplevel-reorder ${FCF_PROTECTION_FLAG}
)
set(${ARCHOBJ_LIBNAME} ${ARCHOBJS_TARGET} PARENT_SCOPE)
endif(arch_files)
endfunction(ARCH2OBJ)
set(KERNEL_IMAGE_OBJCOPY COMMAND ${OBJCOPY_EXECUTABLE} ${PROJECT_BINARY_DIR}/kernel.x --strip-unneeded ${PROJECT_BINARY_DIR}/kernel.x)
if ("${DEBUG}" STREQUAL "1")
set(KERNEL_IMAGE_OBJCOPY )
endif()
set(KERNEL_IMAGE_OBJCOPY
COMMAND ${PROJECT_BINARY_DIR}/add-dbg ${PROJECT_BINARY_DIR}/kernel.x ${PROJECT_BINARY_DIR}/kernel.dbg
${KERNEL_IMAGE_OBJCOPY}
COMMAND mv ${PROJECT_BINARY_DIR}/kernel.x ${PROJECT_BINARY_DIR}/kernel64.x && ${OBJCOPY_EXECUTABLE} -O elf32-i386 ${PROJECT_BINARY_DIR}/kernel64.x ${PROJECT_BINARY_DIR}/kernel.x
)
set(AVAILABLE_MEMORY 8M)
set(QEMU_BIN qemu-system-x86_64)
set(QEMU_FLAGS_COMMON -m ${AVAILABLE_MEMORY} -drive file=${HDD_IMAGE},index=0,media=disk -debugcon stdio -no-reboot)
string(REPLACE ";" " " QEMU_FLAGS_COMMON_STR "${QEMU_FLAGS_COMMON}")
# qemu: Run qemu in non debugging mode
add_custom_target(qemu
COMMAND ${QEMU_BIN} ${QEMU_FLAGS_COMMON} -cpu qemu64 | tee output.log
COMMENT "Executing `${QEMU_BIN} ${QEMU_FLAGS_COMMON_STR} -cpu qemu64`"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMAND reset -I
)
# qemugdb: Run qemu in debugging mode
add_custom_target(qemugdb
COMMAND ${QEMU_BIN} ${QEMU_FLAGS_COMMON} -s -S | tee output.log
COMMENT "Executing `gdb ${QEMU_BIN} ${QEMU_FLAGS_COMMON_STR} -s -S on localhost:1234`"
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
COMMAND reset -I
)

View File

@ -0,0 +1,3 @@
add_subdirectory(x86)
add_subdirectory(x86/64)

View File

@ -0,0 +1 @@
add_subdirectory(userspace)

View File

@ -0,0 +1,2 @@
set(ARCH_USERSPACE_COMPILE_OPTIONS -Wall -Werror -std=gnu11 -g -O0 -m64 -static -nostdinc -fno-builtin -nostdlib -nodefaultlibs -fno-stack-protector -fno-common -Werror=implicit-function-declaration -fno-stack-clash-protection)
set(ARCH_USERSPACE_LINKER_OPTIONS -static)

View File

@ -0,0 +1,5 @@
FILE(GLOB userspace_libc_SOURCES ${CMAKE_CURRENT_LIST_DIR}/*.c)
target_sources(userspace_libc
PRIVATE
${userspace_libc_SOURCES})

View File

@ -0,0 +1,8 @@
#include "types.h"
size_t __syscall(size_t arg1, size_t arg2, size_t arg3, size_t arg4, size_t arg5,
size_t arg6)
{
asm("int $0x80\n" : "=a"(arg1) : "a"(arg1), "b"(arg2), "c"(arg3), "d"(arg4), "S"(arg5), "D"(arg6));
return arg1;
}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,18 @@
# This macro adds a post-build hook to the specified target in order to attach
# SWEB-readable debug info.
function(ADD_DEBUG_INFO TARGET)
set(dbg_binary $<TARGET_FILE:${TARGET}>)
add_custom_command(TARGET ${TARGET}
POST_BUILD
COMMAND "${CMAKE_BINARY_DIR}/add-dbg" "${dbg_binary}" "${dbg_binary}.dbg"
COMMAND "${OBJCOPY_EXECUTABLE}" --remove-section .swebdbg "${dbg_binary}"
COMMAND "${OBJCOPY_EXECUTABLE}" --add-section .swebdbg="${dbg_binary}.dbg"
--set-section-flags .swebdbg=noload,readonly "${dbg_binary}"
COMMAND ${CMAKE_COMMAND} -E remove -f "${dbg_binary}.dbg"
)
# Requires add-dbg to be built first.
add_dependencies(${TARGET} add-dbg)
endfunction(ADD_DEBUG_INFO)

View File

@ -0,0 +1,12 @@
# Macro for defining the "make ${ARCH}" targets
#
# If you want to add a target with multiple variable definitions, this is how you do it:
# MAKE_ARCH_TARGET(my_arch my/arch "-DVAR1=VALUE1;-DVAR2=VALUE2;...")
function(MAKE_ARCH_TARGET TARGET_NAME ARCH_NAME EXTRA_FLAGS)
add_custom_target(${TARGET_NAME}
COMMAND ${PROJECT_SOURCE_DIR}/utils/prompt.sh "rm -fR ${PROJECT_BINARY_DIR}/*: remove all arguments recursively [Y/n]? "
COMMAND rm -fR ${PROJECT_BINARY_DIR}/* || true
COMMAND cmake -DARCH="${ARCH_NAME}" ${EXTRA_FLAGS} ${PROJECT_SOURCE_DIR} ${CMAKE_CROSS_COMPILE_FLAGS}
)
endfunction(MAKE_ARCH_TARGET)

0
pwn/flipper/dist/common/.keep vendored Normal file
View File

18
pwn/flipper/dist/common/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,18 @@
include_directories(
include
../arch/common/include
../arch/${ARCH}/include
../arch/${ARCH}/common/include
../arch/${ARCH}/../common/include
../arch/${ARCH}/../../common/include
include/kernel
include/fs
include/fs/devicefs
include/fs/minixfs
include/fs/pseudofs
include/fs/ramfs
include/util
include/ustl
)
add_subdirectory(source)

0
pwn/flipper/dist/common/include/.keep vendored Normal file
View File

View File

@ -0,0 +1,88 @@
#pragma once
#include "kprintf.h"
enum AnsiColor
{
Ansi_Red = 31,
Ansi_Green = 32,
Ansi_Yellow = 33,
Ansi_Blue = 34,
Ansi_Magenta = 35,
Ansi_Cyan = 36,
Ansi_White = 37,
};
#define OUTPUT_ENABLED 0x80000000
#define OUTPUT_ADVANCED 0x70000000
#define OUTPUT_FLAGS (OUTPUT_ENABLED | OUTPUT_ADVANCED)
#ifndef NOCOLOR
#define DEBUG_FORMAT_STRING "\033[1;%zum[%-11s]\033[0;39m"
#define COLOR_PARAM(flag) (flag & ~OUTPUT_FLAGS), #flag
#else
#define DEBUG_FORMAT_STRING "[%-11s]"
#define COLOR_PARAM(flag) #flag
#endif
#ifndef EXE2MINIXFS
#define debug(flag, ...) do { if (flag & OUTPUT_ENABLED) { kprintfd(DEBUG_FORMAT_STRING, COLOR_PARAM(flag)); kprintfd(__VA_ARGS__); } } while (0)
#endif
//group Block Device
const size_t BD_MANAGER = Ansi_Yellow;
const size_t BD_VIRT_DEVICE = Ansi_Yellow;
//group Console
const size_t KPRINTF = Ansi_Yellow;
//group kernel
const size_t LOCK = Ansi_Yellow | OUTPUT_ENABLED;
const size_t LOADER = Ansi_White | OUTPUT_ENABLED;
const size_t SCHEDULER = Ansi_Yellow | OUTPUT_ENABLED;
const size_t SYSCALL = Ansi_Blue | OUTPUT_ENABLED;
const size_t MAIN = Ansi_Red | OUTPUT_ENABLED;
const size_t THREAD = Ansi_Magenta | OUTPUT_ENABLED;
const size_t USERPROCESS = Ansi_Cyan | OUTPUT_ENABLED;
const size_t PROCESS_REG = Ansi_Yellow | OUTPUT_ENABLED;
const size_t BACKTRACE = Ansi_Cyan | OUTPUT_ENABLED;
const size_t USERTRACE = Ansi_Red | OUTPUT_ENABLED;
//group memory management
const size_t PM = Ansi_Green | OUTPUT_ENABLED;
const size_t PAGEFAULT = Ansi_Green | OUTPUT_ENABLED;
const size_t CPU_ERROR = Ansi_Red | OUTPUT_ENABLED;
const size_t KMM = Ansi_Yellow;
//group driver
const size_t DRIVER = Ansi_Yellow;
const size_t ATA_DRIVER = Ansi_Yellow;
const size_t IDE_DRIVER = Ansi_Yellow;
const size_t MMC_DRIVER = Ansi_Yellow;
//group arch
const size_t A_BOOT = Ansi_Yellow | OUTPUT_ENABLED;
const size_t A_COMMON = Ansi_Yellow;
const size_t A_MEMORY = Ansi_Yellow;
const size_t A_SERIALPORT = Ansi_Yellow;
const size_t A_KB_MANAGER = Ansi_Yellow;
const size_t A_INTERRUPTS = Ansi_Yellow;
//group file system
const size_t FS = Ansi_Yellow;
const size_t RAMFS = Ansi_White;
const size_t DENTRY = Ansi_Blue;
const size_t INODE = Ansi_Blue;
const size_t PATHWALKER = Ansi_Yellow;
const size_t PSEUDOFS = Ansi_Yellow;
const size_t VFSSYSCALL = Ansi_Yellow;
const size_t VFS = Ansi_Yellow | OUTPUT_ENABLED;
const size_t VFS_FILE = Ansi_Yellow;
const size_t SUPERBLOCK = Ansi_Yellow;
//group minix
const size_t M_STORAGE_MANAGER = Ansi_Yellow;
const size_t M_INODE = Ansi_Yellow;
const size_t M_SB = Ansi_Yellow;
const size_t M_ZONE = Ansi_Yellow;

View File

@ -0,0 +1,75 @@
#pragma once
#include <ulist.h>
class BDRequest;
class BDVirtualDevice;
class BDManager
{
public:
BDManager();
~BDManager();
/**
* returns singleton instance
* @return the block device manager instance
*/
static BDManager *getInstance();
/**
* detects all devices present
*/
void doDeviceDetection();
/**
* adds the given device to the manager
* @param dev the device to add
*/
void addVirtualDevice(BDVirtualDevice *dev);
/**
* returns the device with the given number
* @param dev_num the device number
* @return the device
*/
BDVirtualDevice *getDeviceByNumber(uint32 dev_num);
/**
* returns the device with the given name
* @param dev_name the device name
* @return the device
*/
BDVirtualDevice *getDeviceByName(const char *dev_name);
/**
* returns the number of devices in the bd manager
* @return the number of devices
*/
uint32 getNumberOfDevices();
/**
* adds the given request to the device given in the request
* @param bdr the request
*/
void addRequest(BDRequest *bdr);
/**
* calls seviceIRQ on the device the irq with the given number is on
* after that probeIRQ is false
* @param irq_num the irq number
*/
void serviceIRQ(uint32 irq_num);
/**
* gets false when the irq is serviced
*/
bool probeIRQ;
ustl::list<BDVirtualDevice *> device_list_;
protected:
static BDManager *instance_;
};

View File

@ -0,0 +1,101 @@
#pragma once
#include "types.h"
#include "ulist.h"
#include "ustring.h"
class BDDriver;
class BDRequest;
class BDDriver;
class BDRequest;
class BDVirtualDevice
{
public:
BDVirtualDevice(BDDriver *driver, uint32 offset, uint32 num_sectors, uint32 sector_size, const char *name,
bool writable);
void addRequest(BDRequest *command);
uint32 getBlockSize() const
{
return block_size_;
}
uint32 getDeviceNumber() const
{
return dev_number_;
}
BDDriver *getDriver()
{
return driver_;
}
const char *getName()
{
return name_.c_str();
}
uint32 getNumBlocks()
{
return num_sectors_ / (block_size_ / sector_size_);
}
/**
* reads the data from the inode on the current device
* @param offset where to start to read
* @param size number of bytes that should be read
* @param buffer to save the data that has been read
*
*/
virtual int32 readData(uint32 offset, uint32 size, char *buffer);
/**
* reads the data from the inode on the current device
* @param offset where to start to write
* @param size number of bytes that should be written
* @param buffer data, that should be written
*
*/
virtual int32 writeData(uint32 offset, uint32 size, char *buffer);
/**
* the PartitionType is a 8bit field in the PartitionTable of a MBR
* it specifies the FileSystem which is installed on the partition
* @param part_type partition type value to be applied to the Device
*/
void setPartitionType(uint8 part_type);
/**
* getting the PartitionType of this Device (value of the 8bit field
* in Partition Table of the MBR)
* @return the partition type
*/
uint8 getPartitionType(void) const;
void setDeviceNumber(uint32 number)
{
dev_number_ = number;
}
void setBlockSize(uint32 block_size)
{
assert(block_size % sector_size_ == 0);
block_size_ = block_size;
}
private:
BDVirtualDevice();
uint32 dev_number_;
uint32 offset_;
uint32 num_sectors_;
uint32 sector_size_;
uint32 block_size_;
bool writable_;
BDDriver* driver_;
uint8 partition_type_;
ustl::string name_;
};

View File

@ -0,0 +1,165 @@
#pragma once
#include "types.h"
#include <ulist.h>
#include "kstring.h"
#include <ualgo.h>
#include "ustring.h"
class Inode;
/**
* The VFS layer does all management of path names of files, and converts them
* into entries in the dentry before passing allowing the underlying
* file-system to see them. The dentry object associates the component to its
* corresponding inode.
*/
class Dentry
{
protected:
friend class MinixFSInode;
friend class VfsSyscall;
/**
* The pointer to the inode related to this name.
*/
Inode *d_inode_;
/**
* This will point to the parent dentry. For the root of a file-system, or
* for an anonymous entry like that for a file, this points back to the
* containing dentry itself.
*/
Dentry *d_parent_;
/**
* This list_head is used to link together all the children of the dentry.
*/
ustl::list<Dentry*> d_child_;
/**
* For a directory that has had a file-system mounted on it, this points to
* the mount point of that current file-system. For other dentries, this
* points back to the dentry itself.
*/
Dentry *d_mounts_;
public:
/**
* set the inode to the dentry
* @param inode the inode to set
*/
void setInode(Inode *inode);
/**
* release the inode to the dentry
*/
void releaseInode()
{
d_inode_ = 0;
}
/**
* get the inode to dentry
* @return the inode
*/
Inode* getInode()
{
return d_inode_;
}
/**
* return the parent of the dentry
* @return the dentry
*/
Dentry* getParent()
{
return d_parent_;
}
/**
* set the parent dentry
* @param parent the parent dentry to set
*/
void setParent(Dentry *parent)
{
d_parent_ = parent;
}
/**
* return the mount_point of the current file-system
* @return the dentry of the mount point
*/
Dentry* getMountedRoot()
{
return d_mounts_;
}
/**
* set the mount point
* @param mount_point the dentry to set the mount point to
*/
void setMountedRoot(Dentry *mount_point)
{
d_mounts_ = mount_point;
}
/**
* set the child to the dentry
* @param dentry the child dentry to set
* @return 0 on success
*/
int32 setChild(Dentry *dentry);
/**
* check the existance of the child-list
* @return true is empty
*/
bool emptyChild();
/**
* get the number of the child
* @return the number of childs
*/
uint32 getNumChild();
/**
* get the child of the child-list
* @param indes the index of the child to get
* @return the found child dentry
*/
Dentry* getChild(uint32 index);
/**
* return the name of the dentry
* @return the dentry's name
*/
const char* getName();
/**
* This should compare the name with the all names of the d_child_ list.
* It should return the Dentry if it exists the same name in the list,
* @return the dentry found, 0 if doesn't exist.
*/
virtual Dentry* checkName(const char* name);
/**
* remove a child_dentry from the d_child_ list.
* @param child_dentry the child dentry of the curent dentry.
* @return 0 on success
*/
virtual int32 childRemove(Dentry *child_dentry);
/**
* insert a child dentry to the d_child_ list.
* @param child_dentry the child dentry of the current dentry.
*/
virtual void childInsert(Dentry *child_dentry);
public:
Dentry(Inode* inode); // root dentry
Dentry(Inode* inode, Dentry* parent, const ustl::string& name); // named dentry
virtual ~Dentry();
ustl::string d_name_;
};

View File

@ -0,0 +1,6 @@
#pragma once
class Dirent
{
};

View File

@ -0,0 +1,178 @@
#pragma once
#include "types.h"
#include "ulist.h"
class Superblock;
class Inode;
class Dentry;
class FileDescriptor;
#define O_RDONLY 0x0001
#define O_WRONLY 0x0002
#define O_RDWR 0x0004
#define O_CREAT 0x0008
#define O_APPEND 0x0010
#define O_EXCL 0x0020
#define O_NONBLOCK 0x0040
#define O_TRUNC 0x0080
#define O_SYNC 0x0100
#define O_DSYNC 0x0200
#define O_RSYNC O_SYNC
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif
class File
{
public:
uint32 uid;
uint32 gid;
/**
* interna version number.
*/
uint32 version;
protected:
/**
* The superblock pointing to this file
*/
Superblock* f_superblock_;
/**
* The inode associated to the file.
*/
Inode* f_inode_;
/**
* The dentry pointing to this file/
*/
Dentry* f_dentry_;
/**
* The flags specified when the file was opened
*/
uint32 flag_;
/**
* Current offset in the file
*/
l_off_t offset_;
/**
* List of open file descriptors
*/
ustl::list<FileDescriptor*> f_fds_;
public:
/**
* returns the files flag
* @return the flag
*/
uint32 getFlag()
{
return flag_;
}
public:
/**
* The Constructor
* @param inode the files inode
* @param dentry the files dentry
* @param flag the files flag
*/
File(Inode* inode, Dentry* dentry, uint32 flag);
virtual ~File();
virtual FileDescriptor* openFd();
virtual int closeFd(FileDescriptor* fd);
Dentry* getDentry()
{
return f_dentry_;
}
Inode* getInode()
{
return f_inode_;
}
/**
* Sets the file position relative to the start of the file, the end of the
* file or the current file position.
* @param offset is the offset to set.
* @param origin is the on off SEEK_SET, SEEK_CUR and SEEK_END.
* @returns the offset from the start off the file or -1 on failure.
*/
l_off_t lseek(l_off_t offset, uint8 origin);
/**
* not implemented here
* reads from the file
* @param buffer is the buffer where the data is written to
* @param count is the number of bytes to read.
* @param offset is the offset to read from counted from the current file position.
*/
virtual int32 read(char */*buffer*/, size_t /*count*/, l_off_t /*offset*/)
{
return 0;
}
/**
* not implemented here
* write to the file
* @param buffer is the buffer where the data is read from
* @param count is the number of bytes to write.
* @param offset is the offset to write from counted from the current file position
*/
virtual int32 write(const char */*buffer*/, size_t /*count*/, l_off_t /*offset*/)
{
return 0;
}
/**
* Opens the file
* @param inode is the inode the read the file from.
*/
virtual int32 open(uint32)
{
return 0;
}
/**
* not implemented here
* Close the file
* @param inode is close, the superblock has the information, that this
* inode is not use anymore.
*/
virtual int32 close()
{
return 0;
}
/**
* not implemented here
* Flush all off the file's write operations. The File will be written to disk.
* @return is the error code of the flush operation.
*/
virtual int32 flush()
{
return 0;
}
virtual uint32 getSize();
};

View File

@ -0,0 +1,42 @@
#pragma once
#include "types.h"
#include "ulist.h"
#include "umap.h"
#include "Mutex.h"
class File;
class FileDescriptor;
class FileDescriptorList;
class FileDescriptor
{
protected:
size_t fd_;
File* file_;
public:
FileDescriptor ( File* file );
virtual ~FileDescriptor();
uint32 getFd() { return fd_; }
File* getFile() { return file_; }
friend File;
};
class FileDescriptorList
{
public:
FileDescriptorList();
~FileDescriptorList();
int add(FileDescriptor* fd);
int remove(FileDescriptor* fd);
FileDescriptor* getFileDescriptor(uint32 fd);
private:
ustl::list<FileDescriptor*> fds_;
Mutex fd_lock_;
};
extern FileDescriptorList global_fd_list;

View File

@ -0,0 +1,70 @@
#pragma once
#include "types.h"
#include "ustring.h"
#include "Path.h"
class Dentry;
class VfsMount;
class FileSystemInfo
{
protected:
/**
* File system root
*/
Path root_;
/**
* Current working directory
*/
Path pwd_;
public:
FileSystemInfo();
~FileSystemInfo();
FileSystemInfo(const FileSystemInfo& fsi);
/**
* set the ROOT-info to the class
* @param root the root path to set
*/
void setRoot(const Path& path)
{
root_ = path;
}
/**
* set the PWD-info to the class (PWD: print working directory)
* @param path the current path to set
*/
void setPwd(const Path& path)
{
pwd_ = path;
}
/**
* get the ROOT-info (ROOT-directory) from the class
* @return the root path
*/
Path& getRoot()
{
return root_;
}
/**
* get the PWD-info (PWD-directory) from the class
* @return the path of the current directory
*/
Path& getPwd()
{
return pwd_;
}
};
extern FileSystemInfo* default_working_dir;
// you use a different getcwd() method depending on where your cpp is being compiled
// (it can come either from Thread.cpp or from exe2minixfs.cpp)
FileSystemInfo* getcwd();

View File

@ -0,0 +1,54 @@
#pragma once
#include "types.h"
class Superblock;
class Dentry;
#define FS_REQUIRES_DEV 0x0001 // located on a physical disk device
#define FS_NOMOUNT 0x0010 // Filesystem has no mount point
#define MAX_FILE_SYSTEM_TYPES 16
class FileSystemType
{
protected:
const char *fs_name_;
int32 fs_flags_;
public:
FileSystemType(const char *fs_name);
virtual ~FileSystemType();
FileSystemType const &operator =(FileSystemType const &instance)
{
fs_name_ = instance.fs_name_;
fs_flags_ = instance.fs_flags_;
return (*this);
}
const char* getFSName() const;
void setFSName(const char* fs_name);
int32 getFSFlags() const;
void setFSFlags(int32 fs_flags);
/**
* Reads the superblock from the device.
* @param superblock is the superblock to fill with data.
* @param data is the data given to the mount system call.
* @return is a pointer to the resulting superblock.
*/
virtual Superblock *readSuper(Superblock *superblock, void *data) const = 0;
/**
* Creates an Superblock object for the actual file system type.
* @param s_dev a valid device number or -1 if no block device is available
* (e.g. for pseudo file systems)
* @return a pointer to the Superblock object, 0 if wasn't possible to
* create a Superblock with the given device number
*/
virtual Superblock *createSuper(uint32 s_dev) = 0;
};

View File

@ -0,0 +1,283 @@
#pragma once
#include "types.h"
#include "kprintf.h"
#include <ulist.h>
#include <uatomic.h>
#include "Dentry.h"
#include "assert.h"
class File;
class Superblock;
/**
* three possible inode state bits:
*/
#define I_UNUSED 0 // the unused inode state
#define I_DIRTY 1 // Dirty inodes are on the per-super-block s_dirty_ list, and
// will be written next time a sync is requested.
#define I_LOCK 2 //state not implemented
#define A_READABLE 0x0001
#define A_WRITABLE 0x0002
#define A_EXECABLE 0x0004
/**
* five possible inode type bits:
*/
#define I_FILE 0
#define I_DIR 1
#define I_LNK 2
#define I_CHARDEVICE 3
#define I_BLOCKDEVICE 4
/**
* The per-inode flags:
*/
#define MS_NODEV 2 // If this inode is a device special file, it cannot be
// opend.
#define INODE_DEAD 666
class Inode
{
protected:
ustl::list<Dentry*> i_dentrys_;
/**
* The (open) file of this inode.
*/
ustl::list<File*> i_files_;
/**
* the number of Dentry links to this inode.
*/
uint32 i_nlink_;
/**
* the number of runtime references to this inode (loaded Dentrys, open files, ...)
*/
uint32 i_refcount_;
Superblock *superblock_;
/**
* current file size in bytes
*/
uint32 i_size_;
/**
* Inode type: I_FILE, I_DIR, I_LNK, ...
*/
uint32 i_type_;
/**
* There are three possible inode state bits: I_DIRTY, I_LOCK, I_UNUSED.
*/
uint32 i_state_;
/**
* The inodes permission flag
*/
uint32 i_mode_;
public:
/**
* contructor
* @param super_block the superblock to create the inode on
* @param inode_type the inode type
*/
Inode(Superblock *super_block, uint32 inode_type);
virtual ~Inode();
uint32 incRefCount();
uint32 decRefCount();
uint32 numRefs();
uint32 incLinkCount();
uint32 decLinkCount();
uint32 numLinks();
void addDentry(Dentry* dentry);
void removeDentry(Dentry* dentry);
bool hasDentry(Dentry* dentry);
/**
* lookup should check if that name (given by the char-array) exists in the
* directory (I_DIR inode) and should return the Dentry if it does.
* This involves finding and loading the inode. If the lookup failed to find
* anything, this is indicated by returning NULL-pointer.
* @param name the name to look for
* @return the dentry found
*/
virtual Dentry* lookup(const char* /*name*/);
/**
* Called when a file is opened
*/
virtual File* open(Dentry* /*dentry*/, uint32 /*flag*/)
{
return 0;
}
/**
* Called when the last reference to a file is closed
*/
virtual int32 release(File* /*file*/);
/**
* This should create a symbolic link in the given directory with the given
* name having the given value. It should d_instantiate the new inode into
* the dentry on success.
* @param inode the inode to link to
* @param dentry yhe dentry to create the link in
* @param link_name the name of the link to create
* @return 0 on success
*/
virtual int32 symlink(Inode */*inode*/, Dentry */*dentry*/, const char */*link_name*/)
{
return 0;
}
/**
* Create a directory with the given dentry.
* @param the dentry
* @return 0 on success
*/
virtual int32 mkdir(Dentry *);
/**
* Create a file with the given dentry.
* @param dentry the dentry
* @return 0 on success
*/
virtual int32 mkfile(Dentry */*dentry*/);
/**
* Create a special file with the given dentry.
* @param the dentry
* @return 0 on success
*/
virtual int32 mknod(Dentry*);
/**
* Create a hard link with the given dentry.
* @param the dentry
* @return 0 on success
*/
virtual int32 link(Dentry*);
/**
* Unlink the given dentry from the inode.
* @param the dentry
* @return 0 on success
*/
virtual int32 unlink(Dentry*);
/**
* Remove the named directory (if empty).
* @return 0 on success
*/
virtual int32 rmdir(Dentry*);
/**
* change the name to new_name
* @param new name the new name
* @retunr 0 on success
*/
virtual int32 rename(const char* /*new_name*/)
{
return 0;
}
/**
* The symbolic link referred to by the dentry is read and the value is
* copied into the user buffer (with copy_to_user) with a maximum length
* given by the integer.
* @param dentry the dentry
* @param max_length the maximum length
* @return the number of bytes read
*/
virtual int32 readlink(Dentry */*dentry*/, char*, int32 /*max_length*/)
{
return 0;
}
/**
* If the directory (parent dentry) have a directory and a name within that
* directory (child dentry) then the obvious result of following the name
* from the directory would arrive at the child dentry. (for symlink)
* @param prt_dentry the parent dentry
* @param chd_dentry the child dentry
* @return the dentry
*/
virtual Dentry* followLink(Dentry */*prt_dentry*/, Dentry */*chd_dentry*/)
{
return 0;
}
/**
* read the data from the inode
* @param offset the offset from where to start
* @param size the number of bytes to read
* @param buffer where to store the read data
* @return the number of bytes read
*/
virtual int32 readData(uint32 /*offset*/, uint32 /*size*/, char */*buffer*/)
{
return 0;
}
/**
* write the data to the inode
* @param offset the offset from where to start writing
* @param size the number of bytes to write
* @param buffer where to write the data to
* @return number of bytes written
*/
virtual int32 writeData(uint32 /*offset*/, uint32 /*size*/, const char*/*buffer*/)
{
return 0;
}
Superblock* getSuperblock()
{
return superblock_;
}
void setSuperBlock(Superblock * sb)
{
superblock_ = sb;
}
uint32 getType()
{
return i_type_;
}
ustl::list<Dentry*>& getDentrys()
{
return i_dentrys_;
}
uint32 getNumOpenedFile()
{
return i_files_.size();
}
uint32 getSize()
{
return i_size_;
}
uint32 getMode()
{
return i_mode_;
}
int32 flush()
{
return 0;
}
};

View File

@ -0,0 +1,28 @@
#pragma once
#include "types.h"
#include "ustring.h"
class Dentry;
class VfsMount;
class Path
{
public:
Path() = default;
Path(Dentry* dentry, VfsMount* mnt);
Path(const Path&) = default;
Path& operator=(const Path&) = default;
bool operator==(const Path&) const;
Path parent(const Path* global_root = nullptr) const;
int child(const ustl::string& name, Path& out) const;
ustl::string getAbsolutePath(const Path* global_root = nullptr) const;
bool isGlobalRoot(const Path* global_root = nullptr) const;
bool isMountRoot() const;
Dentry* dentry_;
VfsMount* mnt_;
};

View File

@ -0,0 +1,76 @@
#pragma once
#include "types.h"
#include "ustring.h"
class Dentry;
class VfsMount;
class Path;
class FileSystemInfo;
/**
* @enum Type of the last component on LOOKUP_PARENT
*/
enum
{
/**
* The last component is a regular filename
*/
LAST_NORM,
/**
* The last component is "."
*/
LAST_DOT,
/**
* The last component is ".."
*/
LAST_DOTDOT,
};
/**
* @enum Error Codes for the path walk
*/
enum
{
PW_SUCCESS = 0,
/**
* The path was not found
*/
PW_ENOTFOUND,
/**
* The path to look up is invalid
*/
PW_EINVALID
};
class PathWalker
{
public:
/**
* Perform a file system lookup
* @param pathname File pathname to be resolved
* @param pwd Start directory of the file system walk
* @param root Root directory for the file system walk
* @param out Output parameter: Found file path
* @param parent Optional output parameter: Parent directory
* @return Returns 0 on success, != 0 on error
*/
static int32 pathWalk(const char* pathname, const Path& pwd, const Path& root, Path& out, Path* parent = nullptr);
static int32 pathWalk(const char* pathname, FileSystemInfo* fs_info, Path& out, Path* parent_dir = nullptr);
static ustl::string pathPrefix(const ustl::string& path);
static ustl::string lastPathSegment(const ustl::string& path, bool ignore_separator_at_end = false);
private:
static size_t getNextPartLen(const char* path);
static int pathSegmentType(const char* segment);
PathWalker();
~PathWalker();
};

View File

@ -0,0 +1,162 @@
#pragma once
#include "types.h"
#include <ulist.h>
class Iattr;
class Statfs;
class WaitQueue;
class FileSystemType;
class VirtualFileSystem;
class FileDescriptor;
class Dentry;
class Inode;
class File;
class Superblock
{
public:
friend class VirtualFileSystem;
/**
* This records an identification number that has been read from the device
* to confirm that the data on the device corresponds to the file-system
*/
uint64 s_magic_;
protected:
const FileSystemType *s_type_;
/**
* The device that this file-system is mounted on.
*/
size_t s_dev_;
/**
* This is a list of flags which are logically with the flags in each
* inode to detemine certain behaviours. There is one flag which applies
* only to the whole file-system.
* exp: MS_RDONLY
* A file-system with the flag set has been mounted read-only. No writing
* be permitted, and no indirect modification, such as mount time in the
* super-block or access times on files, will be made.
*/
uint64 s_flags_;
/**
* The Dentry refers the root of the file-system. It is normally created by
* loading the root inode from the file-system.
*/
Dentry *s_root_;
/**
* The old Dentry of the mount point of a mounted file system
*/
Dentry *s_mountpoint_;
/**
* A list of dirty inodes.
*/
ustl::list<Inode*> dirty_inodes_;
/**
* A list of used inodes. It is only used to open-file.
*/
ustl::list<Inode*> used_inodes_;
/**
* inodes of the superblock.
*/
ustl::list<Inode*> all_inodes_;
/**
* This is a list of files (linked on f_list) of open files on this
* file-system. It is used, for example, to check if there are any files
* open for write before remounting the file-system as read-only.
*/
ustl::list<File*> s_files_;
public:
/**
* constructor
* @param s_dev the device number of the new filesystem
*/
Superblock(FileSystemType* fs_type, size_t s_dev);
virtual ~Superblock();
/**
* create a new Inode of the superblock
* @param dentry the dentry to create the inode with
* @param type the inode type
* @return the created inode
*/
virtual Inode* createInode(uint32 type) = 0;
/**
* This method is called to read a specific inode from a mounted
* file-system.
* @param inode the inode to read
* @return 0 on success
*/
virtual int32 readInode(Inode* /*inode*/)
{
return 0;
}
/**
* This method is called to write a specific inode to a mounted file-system,
* and gets called on inodes which have been marked dirty.
* @param inode the inode to write
*/
virtual void writeInode(Inode* /*inode*/)
{
}
/**
* This method is called whenever the reference count on an inode reaches 0,
* and it is found that the link count (i_nlink= is also zero. It si
* presumed that the file-system will deal with this situation be
* invalidating the inode in the file-system and freeing up any resourses
* used.
* @param inode the inode to delete
*/
virtual void deleteInode(Inode* /*inode*/);
virtual int fileOpened(File* file);
virtual int fileReleased(File* file);
virtual void releaseAllOpenFiles();
virtual void deleteAllInodes();
/**
* Get the root Dentry of the Superblock
* @return the root dentry
*/
Dentry *getRoot();
/**
* Get the mount point Dentry of the Superblock
* @return the superblocks mount point dentry
*/
Dentry *getMountPoint();
/**
* Set the mount point Dentry of the Superblock
*/
void setMountPoint(Dentry* mountpoint);
/**
* Get the File System Type of the Superblock
* @return the file system type
*/
FileSystemType *getFSType();
};

View File

@ -0,0 +1,108 @@
#pragma once
#include "types.h"
#include "VirtualFileSystem.h"
class Superblock;
class Dentry;
extern VirtualFileSystem vfs;
// Mount flags
// Only MS_RDONLY is supported by now.
/**
* Mount the Filesystem read-only
*/
#define MS_RDONLY 1
class VfsMount
{
protected:
/**
* Points to the parent filesystem on which this filesystem is mounted on.
*/
VfsMount *mnt_parent_;
/**
* Points to the Dentry of the mount directory of this filesystem.
*/
Dentry *mnt_mountpoint_;
/**
* Points to the Dentry of the root directory of this filesystem.
*/
Dentry *mnt_root_;
/**
* Points to the superblock object of this filesystem.
*/
Superblock *mnt_sb_;
/**
* The mnt_flags_ field of the descriptor stores the value of several flags
* that specify how some kinds of files in the mounted filesystem are
* handled.
*/
int32 mnt_flags_;
public:
VfsMount();
/**
* constructor
* @param parent the parent dentry of the mount point
* @param mountpoint the mount points dentry
* @param root the root dentry
* @param superblock the superblock mounted
* @param flags the flags
*/
VfsMount(VfsMount* parent, Dentry * mountpoint, Dentry* root,
Superblock* superblock, int32 flags);
virtual ~VfsMount();
/**
* get the parent-VfsMount of the VfsMount
* @return the parent-VfsMount
*/
VfsMount *getParent() const;
/**
* get the mount-point of the VfsMount
* @return the mount point dentry
*/
Dentry *getMountPoint() const;
/**
* get the ROOT-directory of the VfsMount
* @return the root dentry
*/
Dentry *getRoot() const;
/**
* get the superblock fo the VfsMount
* @return the superblock
*/
Superblock *getSuperblock() const;
/**
* get the flags
* @return the flags
*/
int32 getFlags() const;
/**
* NOTE: only used as workaround
*/
void clear();
bool isRootMount() const;
};

View File

@ -0,0 +1,150 @@
#pragma once
#include "types.h"
class Dirent;
class Dentry;
class VfsMount;
class FileDescriptor;
class VfsSyscall;
class Path;
class FileSystemInfo;
class VfsSyscall
{
public:
/**
* make a new directory.
* i.e. im the path "/file/test/" create a new directory with the name
* "dir". => the new_dir ist "/file/test/dir"
* @param pathname the new directory.
* @param type the permission.
* @return On success, zero is returned. On error, -1 is returned.
*/
static int32 mkdir(const char* pathname, int32 /*type*/);
/**
* The readdir() displays or saves the names from all childs into buffer and returns a pointer
* to a Dirent.
* @param pathname the destination-directory.
* @param buffer the buffer the output is saved to
* @param size the size of buffer in bytes
* @return the dirent
*/
static Dirent* readdir(const char* pathname, char* buffer = 0, size_t size = 0);
/**
* chdir() changes the current directory to the specified directory.
* @param dir the destination-directory.
* @return On success, zero is returned. On error, -1 is returned.
*/
static int32 chdir(const char* pathname);
/**
* delete a directory, which must be empty.
* @param pathname the removed directory
* @return On success, zero is returned. On error, -1 is returned.
*/
static int32 rmdir(const char* pathname);
/**
* remove a directory (which must be empty) or a file
* @param pathname the removed directory or file
* @return On success, zero is returned. On error, -1 is returned.
*/
static int32 rm(const char* pathname);
/**
* The open() is used to convert a pathname into a file descriptor, if the
* pathname does not exist, create a new file.
* @param pathname the file pathname
* @param flag specified when the file was opened
* @return On success, file descriptor is returned. On error, -1 is returned.
*/
static int32 open(const char* pathname, uint32 flag);
/**
* The close() closes a file descriptor.
* @param fd the file descriptor
* @return On success, zero is returned. On error, -1 is returned.
*/
static int32 close(uint32 fd);
/**
* The read() attempts to read up to count bytes from file descriptor fd
* into the buffer starting at buffter.
* @param fd the file descriptor
* @param buffer the buffer that to read the date
* @param count the size of the byte
* @return On success, the number of bytes read is returned (zero indicates
* end of file), and the file position is advanced by this number.
* On error, -1 is returned.
*/
static int32 read(uint32 fd, char* buffer, uint32 count);
/**
* Sets the file position relative to the start of the file, the end of the
* file or the current file position.
* @param fd the file descriptor
* @param offset is the offset to set.
* @param origin is the on off SEEK_SET, SEEK_CUR and SEEK_END.
* @returns the offset from the start off the file or -1 on failure.
*/
static l_off_t lseek(uint32 fd, l_off_t offset, uint8 origin);
/**
* write writes up to count bytes to the file referenced by the file
* descriptor fd from the buffer starting at buf.
* @param fd the file descriptor
* @param buffer the buffer that to store the date
* @param count the size of the byte
* @return On success, the number of bytes written are returned (zero
* indicates nothing was written). On error, -1 is returned
*/
static int32 write(uint32 fd, const char *buffer, uint32 count);
/**
* flushes the file with the given file descriptor to the disc
* so that changes in the system are written to disc
* @param fd the file descriptor
* @return 0 on success, -1 on error
*/
static int32 flush(uint32 fd);
/**
* mounts a file system
* @param device_name the device name i.e. ida
* @param dir_name the directory name where to mount the filesystem
* @param file_system_name the file system name i.e. minixfs
* @param flag the flag indicates if mounted readonly etc.
* @return 0 on success
*/
static int32 mount(const char *device_name, const char *dir_name, const char *file_system_name, int32 flag);
/** unmounts a filesystem
* @param dir_name the directory where the filesystem to unmount is mounted
* @param flag not used
* @return 0 on success
*/
static int32 umount(const char *dir_name, int32 flag);
/**
* returns the size of a file
* @param fd the file looking for
* @return the size
*/
static uint32 getFileSize(uint32 fd);
/**
* get the File descriptor object from the global variable
* @param the fd int
* @return the file descriptor object
*/
static FileDescriptor* getFileDescriptor(uint32 fd);
private:
VfsSyscall();
~VfsSyscall();
};

View File

@ -0,0 +1,106 @@
#pragma once
#include "types.h"
#include <ustl/ulist.h>
/**
* File system flag indicating if the system in question requires an device.
*/
#define FS_REQUIRES_DEV 0x0001 // located on a physical disk device
#define FS_NOMOUNT 0x0010 // Filesystem has no mount point
/**
* The maximal number of file system types.
*/
#define MAX_FILE_SYSTEM_TYPES 16
class Superblock;
class FileSystemType;
class VfsMount;
class Dentry;
class FileSystemInfo;
class VirtualFileSystem
{
protected:
ustl::list<Superblock*> superblocks_;
ustl::list<VfsMount*> mounts_;
ustl::list<FileSystemType*> file_system_types_;
public:
void initialize();
VirtualFileSystem();
~VirtualFileSystem();
/**
* register the file-system-type to the vfs
* @param file_system_type the file system type to register
* @return 0 on success, -1 if a file-system-type with that name has
* already been registered
*/
int32 registerFileSystem(FileSystemType *file_system_type);
/**
* unregister the file-system-typt to the vfs
* @param file_system_type the file system type to unregister
* @return 0 on success
*/
int32 unregisterFileSystem(FileSystemType *file_system_type);
/**
* The getFsType function receives a filesystem name as its parameter, scans
* the list of registered filesystems looking at the fs_name field of their
* descriptors, and returns a pointer to the corresponding FileSystemType
* object, if is present.
* @param fs_name the name of the filesystem
* @return the file system type
*/
FileSystemType *getFsType(const char* fs_name);
/**
* found the VfsMount from mounts_ list with given dentry.
* @param dentry the mount-point-dentry or root-dentry
* @param is_mount_point if it is false, check with root-dentry,
* else mount-point-dentry
*/
VfsMount *getVfsMount(const Dentry* dentry, bool is_root = false);
/**
* mount the dev_name (device name) to the directory specified by dir_name.
* @param dev_name the device file name of the block device storing the
* filesystem. Shall be a empty string to mount pseudo
* file sytems.
* @param dir_name the mount pointer directory
* @param fs_name the name of the type of filesystem to be mounted
* @param flags the mount flags
* @param data contain arbitray fs-dependent information (or be NULL)
* @return On success, zero is returned. On error, -1 is returned.
*/
int32 mount(const char* dev_name, const char* dir_name, const char* fs_name, uint32 flags/*, void *data*/);
/**
* unmount the filesystem
* @param dir_name the mount pointer direcotry or (block devie block filename)
* @param flags the umount flags
* @return On success, zero is returned. On error, -1 is returned.
*/
int32 umount(const char* dir_name, uint32 flags);
/**
* mount the ROOT to the VFS. (special of the mount)
* @param fs_name the name of the type of filesystem to be mounted
* @param flags the mount flags
* @return On success, zero is returned. On error, -1 is returned.
*/
FileSystemInfo *rootMount(const char* fs_name, uint32 flags);
/**
* umount the ROOT from the VFS (special of the umount)
* @return On success, zero is returned. On error, -1 is returned.
*/
int32 rootUmount();
};
extern VirtualFileSystem vfs;

View File

@ -0,0 +1,44 @@
#pragma once
#include "fs/Superblock.h"
#include "fs/ramfs/RamFSSuperblock.h"
class Inode;
class Superblock;
class CharacterDevice;
class DeviceFSType;
class DeviceFSSuperBlock : public RamFSSuperblock
{
public:
static const char ROOT_NAME[];
static const char DEVICE_ROOT_NAME[];
virtual ~DeviceFSSuperBlock();
/**
* addsa new device to the superblock
* @param inode the inode of the device to add
* @param node_name the device name
*/
void addDevice(Inode* inode, const char* node_name);
/**
* Access method to the singleton instance
*/
static DeviceFSSuperBlock* getInstance();
private:
/**
* Constructor
* @param s_root the root Dentry of the new Filesystem
* @param s_dev the device number of the new Filesystem
*/
DeviceFSSuperBlock(DeviceFSType* fs_type, uint32 s_dev);
protected:
static DeviceFSSuperBlock* instance_;
};

View File

@ -0,0 +1,34 @@
#pragma once
#include "fs/FileSystemType.h"
#include "fs/ramfs/RamFSType.h"
class DeviceFSType : public RamFSType
{
public:
DeviceFSType();
virtual ~DeviceFSType();
/**
* Reads the superblock from the device.
* @param superblock is the superblock to fill with data.
* @param data is the data given to the mount system call.
* @return is a pointer to the resulting superblock.
*/
virtual Superblock *readSuper(Superblock *superblock, void *data) const;
/**
* Creates an Superblock object for the actual file system type.
* @param root the root dentry of the new superblock
* @param s_dev the device number of the new superblock
* @return a pointer to the Superblock object
*/
virtual Superblock *createSuper(uint32 s_dev);
static DeviceFSType* getInstance();
protected:
static DeviceFSType* instance_;
};

View File

@ -0,0 +1,43 @@
#pragma once
#include "File.h"
class MinixFSFile : public File
{
public:
/**
* constructor
* @param inode the inode of the file
* @param dentry the dentry
* @param flag the flag i.e. readonly
*/
MinixFSFile(Inode* inode, Dentry* dentry, uint32 flag);
virtual ~MinixFSFile();
/**
* reads from the file
* @param buffer the buffer where the data is written to
* @param count the number of bytes to read
* @param offset the offset to read from counted from the current file position
* @return the number of bytes read
*/
virtual int32 read(char *buffer, size_t count, l_off_t offset);
/**
* writes to the file
* @param buffer the buffer where the data is read from
* @param count the number of bytes to write
* @param offset the offset to write from counted from the current file position
* @return the number of bytes written
*/
virtual int32 write(const char *buffer, size_t count, l_off_t offset);
/**
* writes all data to disc
* @return 0 on success
*/
virtual int32 flush();
};

View File

@ -0,0 +1,141 @@
#pragma once
#include "types.h"
#include "kstring.h"
#include "Inode.h"
#include "MinixFSZone.h"
#include <ulist.h>
class MinixFSInode : public Inode
{
friend class MinixFSSuperblock;
protected:
/**
* the zones storing the addresses of memory of this inode
*/
MinixFSZone *i_zones_;
/**
* the inode number (the first inode has the i_num 1 on a minix file system)
*/
uint32 i_num_;
/**
* reads all the inode's children from disc and creates their objects
*/
virtual void loadChildren();
public:
/**
* basic constructor
* @param super_block the superblock the inode is on
* @param inode_type the inode type (I_FILE, I_DIR)
*/
MinixFSInode(Superblock *super_block, uint32 inode_type);
/**
* constructor of an inode existing on disc with all data given
* @param super_block the superblock the inode is on
* @param i_mode the mode containing the rights and the inode type (I_FILE, I_DIR)
* @param i_size the inodes size
* @param i_nlinks the number of links to this inode
* @param i_zones the first 9 zone addresses
* @param i_num the inode number
*/
MinixFSInode(Superblock *super_block, uint16 i_mode, uint32 i_size, uint16 i_nlinks, uint32* i_zones, uint32 i_num);
virtual ~MinixFSInode();
/**
* lookup checks if that name (given by the char-array) exists in the
* directory (I_DIR inode) and returns the Dentry if it does.
* This involves finding and loading the inode. If the lookup failed to find
* anything, this is indicated by returning NULL-pointer.
* @param name the name to look for
* @return the dentry found or NULL otherwise
*/
virtual Dentry* lookup(const char *name);
/**
* Called when a file is opened
*/
virtual File* open(Dentry* dentry, uint32 /*flag*/);
/**
* creates a directory with the given dentry. It is only used to with directory.
* @param dentry the dentry to create with
* @return 0 on success
*/
virtual int32 mkdir(Dentry *dentry);
virtual int32 link(Dentry* dentry);
virtual int32 unlink(Dentry* dentry);
/**
* removes the directory (if it is empty)
* @return 0 on success
*/
virtual int32 rmdir(Dentry* dentry);
/**
* creates a directory with the given dentry.
* @param dentry the dentry
* @return 0 on success
*/
virtual int32 mknod(Dentry *dentry); // no dir no file
/**
* creates a file with the given dentry.
* @param dentry the dentry
* @return 0 on success
*/
virtual int32 mkfile(Dentry *dentry);
/**
* read the data from the inode
* @param offset offset byte
* @param size the size of data that read from this inode
* @param buffer the dest char-array to store the data
* @return the number of bytes read
*/
virtual int32 readData(uint32 offset, uint32 size, char *buffer);
/**
* write the data to the inode
* @param offset offset byte
* @param size the size of data that write to this inode (data_)
* @param buffer the src char-array
* @return the number of bytes written
*/
virtual int32 writeData(uint32 offset, uint32 size, const char *buffer);
/**
* flushes the inode to the file system
* @return 0 on success
*/
virtual int32 flush();
private:
/**
* writes the inode dentry to disc
* @param dest_i_num the inode number to write the dentry to
* @param src_i_num the inode number to write
* @param name the name to write there
*/
void writeDentry(uint32 dest_i_num, uint32 src_i_num, const char* name);
/**
* finding the position of the dentry of the given inode in this inode
* @param i_num the inode number to look for
* @return the dentry position
*/
int32 findDentry(uint32 i_num);
/**
* true if the inodes children are allready loaded
*/
bool children_loaded_;
};

View File

@ -0,0 +1,201 @@
#pragma once
#include "Superblock.h"
#include "MinixStorageManager.h"
#include "umap.h"
class Inode;
class MinixFSInode;
class Superblock;
class MinixFSType;
class MinixFSSuperblock : public Superblock
{
public:
friend class MinixFSInode;
friend class MinixFSZone;
friend class MinixStorageManager;
MinixFSSuperblock(MinixFSType* fs_type, size_t s_dev, uint64 offset);
virtual ~MinixFSSuperblock();
/**
* creates one new inode of the superblock
* @param type the file type of the new inode (I_DIR, I_FILE)
* @return the new inode
*/
virtual Inode* createInode(uint32 type);
/**
* reads one inode from the mounted file system
* @param inode the inode to read
* @return 0 on success
*/
virtual int32 readInode(Inode* inode);
/**
* writes the inode from the mounted file system
* @param inode the inode to write
*/
virtual void writeInode(Inode* inode);
/**
* removes one inode from the file system and frees all its resources
* @param inode the inode to delete
*/
virtual void deleteInode(Inode* inode);
/**
* add an inode to the all_inodes_ data structures
* @param inode to add
*/
void all_inodes_add_inode(Inode* inode);
/**
* remove an inode to the all_inodes_ data structures
* @param inode to remove
*/
void all_inodes_remove_inode(Inode* inode);
/**
* allocates one zone on the file system
* @return the zone index
*/
virtual uint16 allocateZone();
/**
* frees zone on the file system
* @param index the zone index
*/
virtual void freeZone(uint16 index);
protected:
/**
* creates an Inode object with the given number from the file system
* @param i_num the inode number
* @return the Inode object
*/
MinixFSInode *getInode(uint16 i_num);
/**
* creates an Inode object with the given number from the file system
* this overloaded version should be used; directories usually have
* "." and ".." entries, which are pointing to already loaded inodes!!!
* by now this method is only called from MinixFSInode::loadChildren
* @param i_num the inode number
* @param is_already_loaded should be set to true if already loaded
* @return the Inode object
*/
MinixFSInode *getInode(uint16 i_num, bool &is_already_loaded);
/**
* reads one Zone from the file system to the given buffer
* @param zone the zone index to read
* @param buffer the buffer to write in
*/
void readZone(uint16 zone, char *buffer);
/**
* reads the given number of blocks from the file system to the given buffer
* @param block the index of the block to start reading
* @param num_blocks the number of blcoks to read
* @param buffer the buffer to write in
*/
void readBlocks(uint16 block, uint32 num_blocks, char *buffer);
/**
* writes one zone from the given buffer to the file system
* @param zone the zone index to write
* @param buffer the buffer to write
*/
void writeZone(uint16 zone, char *buffer);
/**
* writes the given number of blcoks to the file system from the given buffer
* @param block the index of the first block to write
* @param num_blocks the number of blocks to write
* @param buffer the buffer to write
*/
void writeBlocks(uint16 block, uint32 num_blocks, char *buffer);
/**
* writes the given number of bytes to the filesystem
* the bytes must be on one block
* @param block the block to write to
* @param offset the offset on the block
* @param size the number of bytes to write
* @param buffer the buffer with the bytes to write
* @return the number of bytes written
*/
int32 writeBytes(uint32 block, uint32 offset, uint32 size, char *buffer);
/**
* reads the given number of bytes from the disc
* the bytes must be on one block
* @param block the block to read from
* @param offset the offset on the block
* @param size the number of bytes to read
* @param buffer the buffer to write to
* @return the number of bytes read
*/
int32 readBytes(uint32 block, uint32 offset, uint32 size, char *buffer);
/**
* reads the fs header
*/
void readHeader();
private:
/**
* reads the root inode and its children from the filesystem
*/
void initInodes();
/**
* # usable inodes on the minor device
*/
uint32 s_num_inodes_;
/**
* # of blocks used by inode bit map
*/
uint16 s_num_inode_bm_blocks_;
/**
* # of blocks used by zone bit map
*/
uint16 s_num_zone_bm_blocks_;
/**
* number of first datazone
*/
uint16 s_1st_datazone_;
/**
* log2 of blocks/zone
*/
uint16 s_log_zone_size_;
/**
* maximum file size on this device
*/
uint32 s_max_file_size_;
uint32 s_zones_;
uint16 s_block_size_;
uint8 s_disk_version_;
MinixStorageManager* storage_manager_;
ustl::map<uint32, Inode*> all_inodes_set_;
/**
* pointer to self for compatability
*/
Superblock* superblock_;
/**
* offset in the image file (in image util)
*/
uint64 offset_;
};

View File

@ -0,0 +1,26 @@
#pragma once
#include "FileSystemType.h"
class MinixFSType : public FileSystemType
{
public:
MinixFSType();
virtual ~MinixFSType();
/**
* reads the superblock from the device
* @param superblock a pointer to the resulting superblock
* @param data the data given to the mount system call
* @return the superblock
*/
virtual Superblock *readSuper(Superblock *superblock, void *data) const;
/**
* creates an Superblock object for the actual file system type
* @param root the root dentry
* @param s_dev the device number
*/
virtual Superblock *createSuper(uint32 s_dev);
};

View File

@ -0,0 +1,39 @@
#pragma once
#include "types.h"
class MinixFSSuperblock;
class MinixFSZone
{
public:
/**
* constructor
* @param superblock the superblock
* @param zones the zone array from the file system
*/
MinixFSZone(MinixFSSuperblock *superblock, uint32 *zones);
~MinixFSZone();
uint32 getZone(uint32 index);
void setZone(uint32 index, uint32 zone);
void addZone(uint32 zone);
uint32 getNumZones()
{
return num_zones_;
}
void flush(uint32 inode_num);
void freeZones();
private:
MinixFSSuperblock *superblock_;
uint32 direct_zones_[10];
uint32 *indirect_zones_;
uint32 *double_indirect_linking_zone_;
uint32 **double_indirect_zones_;
uint32 num_zones_;
};

View File

@ -0,0 +1,45 @@
#pragma once
#include "StorageManager.h"
#include "types.h"
#include "minix_fs_consts.h"
class MinixFSSuperblock;
class MinixStorageManager : public StorageManager
{
public:
/**
* constructor
* @param bm_buffer the buffer with the inode and zone bitmaps from disc
* @param num_inode_bm_blocks the number of blocks used for the inode bitmap
* @param num_zone_bm_blocks the number of blocks used for the zone bitmap
* @param num_inodes the max number of inodes
* @param num_zones the max number of zones
*/
MinixStorageManager(char *bm_buffer, uint16 num_inode_bm_blocks, uint16 num_zone_bm_blocks, uint16 num_inodes,
uint16 num_zones);
virtual ~MinixStorageManager();
virtual size_t allocZone();
virtual size_t allocInode();
virtual void freeZone(size_t index);
virtual void freeInode(size_t index);
virtual bool isInodeSet(size_t index);
virtual uint32 getNumUsedInodes();
void flush(MinixFSSuperblock *superblock);
void printBitmap();
private:
size_t curr_zone_pos_;
size_t curr_inode_pos_;
uint32 num_inode_bm_blocks_;
uint32 num_zone_bm_blocks_;
};

View File

@ -0,0 +1,44 @@
#pragma once
#include "Bitmap.h"
#include "types.h"
class StorageManager
{
public:
/**
* constructor
* @param num_inodes the max number of inodes
* @param num_zones the max number of zones
*/
StorageManager(uint16 num_inodes, uint16 num_zones);
virtual ~StorageManager();
/**
* frees the zone at the given index
* @param index the zone index
*/
virtual void freeZone(size_t index) = 0;
/**
* frees the inode at the given index
* @param index the inode index
*/
virtual void freeInode(size_t index) = 0;
/**
* checks if inode is set
* @param index the inode index
* @return true if the inode is set
*/
virtual bool isInodeSet(size_t index) = 0;
protected:
Bitmap inode_bitmap_;
Bitmap zone_bitmap_;
};

View File

@ -0,0 +1,16 @@
#pragma once
#define V3_OFFSET ((superblock_->s_magic_==MINIX_V3) ? 1 : 0)
#define V3_ARRAY(PTR,IDX) ((superblock_->s_magic_==MINIX_V3) ? ((uint32*)(PTR))[(IDX)] : ((uint16*)(PTR))[(IDX)])
#define SET_V3_ARRAY(PTR,IDX,VAL) do { if (superblock_->s_magic_==MINIX_V3) ((uint32*)(PTR))[(IDX)] = VAL; else ((uint16*)(PTR))[(IDX)] = VAL; } while (0)
#define NUM_ZONE_ADDRESSES ((superblock_->s_magic_==MINIX_V3) ? 256 : 512)
#define ZONE_SIZE 1024U
#define BLOCK_SIZE 1024U
#define INODE_BYTES ((superblock_->s_magic_==MINIX_V3) ? 4 : 2)
#define INODE_SIZE ((superblock_->s_magic_==MINIX_V3) ? 64 : 32)
#define INODES_PER_BLOCK ((superblock_->s_magic_==MINIX_V3) ? 16 : 32)
#define DENTRY_SIZE ((superblock_->s_magic_==MINIX_V3) ? 64 : 32)
#define MAX_NAME_LENGTH ((superblock_->s_magic_==MINIX_V3) ? 60 : 30)
#define NUM_ZONES ((superblock_->s_magic_==MINIX_V3) ? 10 : 9)
#define MINIX_V3 0x4d5a

View File

@ -0,0 +1,61 @@
#pragma once
#include "fs/File.h"
class RamFSFile: public File
{
public:
RamFSFile ( Inode* inode, Dentry* dentry, uint32 flag );
virtual ~RamFSFile();
/**
* Sets the file position relative to the start of the file, the end of
* the file or the current file position.
* @param offset is the offset to set.
* @param origin is the on off SEEK_SET, SEEK_CUR and SEEK_END.
* @return the offset from the start off the file or -1 on failure.
*/
l_off_t llSeek ( l_off_t offset, uint8 origin );
/**
* reads from the file
* @param buffer is the buffer where the data is written to
* @param count is the number of bytes to read.
* @param offset is the offset to read from counted from the start of the file.
* @return the number of bytes read
*/
virtual int32 read ( char *buffer, size_t count, l_off_t offset );
/**
* writes to the file
* @param buffer is the buffer where the data is read from
* @param count is the number of bytes to write.
* @param offset is the offset to write from counted from the start of the file.
* @return the number of bytes written
*/
virtual int32 write ( const char *buffer, size_t count, l_off_t offset );
/**
* Opens the file
* @param flag how to open the file
* @return the filedescriptor
*/
virtual int32 open ( uint32 flag );
/**
* Closes the file
* @return 0 on success
*/
virtual int32 close();
/**
* Flushes all off the file's write operations. The File will be written to disk.
* @return is the error code of the flush operation.
*/
virtual int32 flush();
};

View File

@ -0,0 +1,40 @@
#pragma once
#include "types.h"
#include "fs/Inode.h"
class RamFSInode : public Inode
{
protected:
char* data_;
public:
/**
* constructor
* @param super_block the superblock to create the inode on
* @param inode_type the inode type
*/
RamFSInode ( Superblock *super_block, uint32 inode_type );
virtual ~RamFSInode();
/**
* Called when a file is opened
*/
virtual File* open(Dentry* dentry, uint32 /*flag*/);
/// read the data from the inode
/// @param offset offset byte
/// @param size the size of data that read from this inode
/// @buffer the dest char-array to store the data
/// @return On successe, return 0. On error, return -1.
virtual int32 readData ( uint32 offset, uint32 size, char *buffer );
/// write the data to the inode
/// @param offset offset byte
/// @param size the size of data that write to this inode (data_)
/// @buffer the src char-array
/// @return On successe, return 0. On error, return -1.
virtual int32 writeData ( uint32 offset, uint32 size, const char *buffer );
};

View File

@ -0,0 +1,53 @@
#pragma once
#include "fs/Superblock.h"
class Inode;
class Superblock;
class RamFSType;
class RamFSSuperblock : public Superblock
{
public:
/**
* constructor
* @param s_root the root dentry of the new filesystem
* @param s_dev the device number of the new filesystem
*/
RamFSSuperblock (RamFSType* type, uint32 s_dev );
virtual ~RamFSSuperblock();
/**
* create a new Inode of the superblock, mknod with dentry, add in the list.
* @param dentry the dentry to create the new inode with
* @param type the inode type
* @return the inode
*/
virtual Inode* createInode (uint32 type );
/**
* This method is called to read a specific inode from a mounted file-system.
* @param inode the inode to read
* @return 0 on success
*/
virtual int32 readInode ( Inode* inode );
/**
* This method is called to write a specific inode to a mounted file-system,
* and gets called on inodes which have been marked dirty.
* @param inode the inode to write
*/
virtual void writeInode ( Inode* inode );
/**
* This method is called whenever the reference count on an inode reaches 0,
* and it is found that the link count (i_nlink= is also zero. It is
* presumed that the file-system will deal with this situation be
* invalidating the inode in the file-system and freeing up any resourses
* used.
* @param inode the inode to delete
*/
virtual void deleteInode ( Inode* inode );
};
//-----------------------------------------------------------------------------

View File

@ -0,0 +1,25 @@
#pragma once
#include "fs/FileSystemType.h"
class RamFSType : public FileSystemType
{
public:
RamFSType();
virtual ~RamFSType();
/**
* Reads the superblock from the device.
* @param superblock is the superblock to fill with data.
* @param data is the data given to the mount system call.
* @return is a pointer to the resulting superblock.
*/
virtual Superblock *readSuper(Superblock *superblock, void *data) const;
/**
* Creates an Superblock object for the actual file system type.
* @return a pointer to the Superblock object
*/
virtual Superblock *createSuper(uint32 s_dev);
};

View File

View File

@ -0,0 +1,21 @@
#pragma once
#define fd_stdin 0
#define fd_stdout 1
#define fd_stderr 2
#define sc_exit 1
#define sc_fork 2
#define sc_read 3
#define sc_write 4
#define sc_open 5
#define sc_close 6
#define sc_lseek 19
#define sc_pseudols 43
#define sc_outline 105
#define sc_sched_yield 158
#define sc_createprocess 191
#define sc_trace 252
#define sc_flip_bit 69

View File

@ -0,0 +1,24 @@
License for the USTL, forked from https://github.com/msharov/ustl
The MIT License
Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,98 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "assert.h"
#include "ualgobase.h"
/// The ustl namespace contains all ustl classes and algorithms.
namespace ustl {
class istream;
class ostream;
class ostringstream;
/// \class cmemlink cmemlink.h ustl.h
/// \ingroup MemoryManagement
///
/// \brief A read-only pointer to a sized block of memory.
///
/// Use this class the way you would a const pointer to an allocated unstructured block.
/// The pointer and block size are available through member functions and cast operator.
///
/// Example usage:
///
/// \code
/// void* p = malloc (46721);
/// cmemlink a, b;
/// a.link (p, 46721);
/// assert (a.size() == 46721));
/// b = a;
/// assert (b.size() == 46721));
/// assert (b.DataAt(34) == a.DataAt(34));
/// assert (0 == memcmp (a, b, 12));
/// \endcode
///
class cmemlink {
public:
typedef char value_type;
typedef const value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type reference;
typedef value_type const_reference;
typedef size_t size_type;
typedef uint32_t written_size_type;
typedef ptrdiff_t difference_type;
typedef const_pointer const_iterator;
typedef const_iterator iterator;
typedef const cmemlink& rcself_t;
public:
inline cmemlink (void) : _data (nullptr), _size (0) { }
inline cmemlink (const void* p, size_type n) : _data (const_pointer(p)), _size (n) { assert (p || !n); }
inline cmemlink (const cmemlink& l) : _data (l._data), _size (l._size) {}
inline virtual ~cmemlink (void) noexcept {}
void link (const void* p, size_type n);
inline void link (const cmemlink& l) { link (l.begin(), l.size()); }
inline void link (const void* first, const void* last) { link (first, distance (first, last)); }
inline void relink (const void* p, size_type n);
virtual void unlink (void) noexcept { _data = nullptr; _size = 0; }
inline rcself_t operator= (const cmemlink& l) { link (l); return *this; }
bool operator== (const cmemlink& l) const noexcept;
inline void swap (cmemlink& l) { ::ustl::swap (_data, l._data); ::ustl::swap (_size, l._size); }
inline size_type size (void) const { return _size; }
inline size_type max_size (void) const { return size(); }
inline size_type readable_size (void) const { return size(); }
inline bool empty (void) const { return !size(); }
inline const_pointer data (void) const { return _data; }
inline const_pointer cdata (void) const { return _data; }
inline iterator begin (void) const { return iterator (cdata()); }
inline iterator iat (size_type i) const { assert (i <= size()); return begin() + i; }
inline iterator end (void) const { return iat (size()); }
inline void resize (size_type n) { _size = n; }
inline void read (istream&) { assert (!"ustl::cmemlink is a read-only object."); }
void write (ostream& os) const;
size_type stream_size (void) const noexcept;
void text_write (ostringstream& os) const;
void write_file (const char* filename, int mode = 0644) const;
private:
const_pointer _data; ///< Pointer to the data block (const)
size_type _size; ///< size of the data block
};
//----------------------------------------------------------------------
/// A fast alternative to link which can be used when relinking to the same block (i.e. when it is resized)
inline void cmemlink::relink (const void* p, size_type n)
{
_data = reinterpret_cast<const_pointer>(p);
_size = n;
}
//----------------------------------------------------------------------
/// Use with cmemlink-derived classes to link to a static array
#define static_link(v) link (VectorBlock(v))
} // namespace ustl

View File

@ -0,0 +1,261 @@
// config.h - Generated from config.h.in by configure.
#pragma once
// Define to the one symbol short name of this package.
#define USTL_NAME "ustl"
// Define to the full name and version of this package.
// More or less. Was manually merged and updated from version ustl v2.2-3-gf0abf84 with SWEB specific changes. config.h file was mostly left as it is and not updated
// Based on ustl upstream commit c19d8291a471c47c808b5ef303f163df166cd388
#define USTL_STRING "ustl v2.6-2-gc19d829"
// Define to the version of this package.
#define USTL_VERSION 0x260
// Define to the address where bug reports for this package should be sent.
#define USTL_BUGREPORT "Mike Sharov <msharov@users.sourceforge.net>"
/// Define to 1 if you want stream operations to throw exceptions on
/// insufficient data or insufficient space. All these errors should
/// be preventable in output code; the input code should verify the
/// data in a separate step. It slows down stream operations a lot,
/// but it is your decision. By default only debug builds throw.
///
#define WANT_STREAM_BOUNDS_CHECKING 0
/// Define to 1 if you want backtrace symbols demangled.
/// This adds some 15k to the library size, and requires that you link it and
/// any executables you make with the -rdynamic flag (increasing library size
/// even more). By default only the debug build does this.
#undef WANT_NAME_DEMANGLING
/// Define to 1 if you want to build without libstdc++
#define WITHOUT_LIBSTDCPP 1
/// Define GNU extensions if unavailable.
#ifndef __GNUC__
/// GCC (and some other compilers) define '__attribute__'; ustl is using this
/// macro to alert the compiler to flag inconsistencies in printf/scanf-like
/// function calls. Just in case '__attribute__' is undefined, make a dummy.
///
#ifndef __attribute__
#define __attribute__(p)
#endif
#endif
#define WEAKALIAS(sym) __attribute__((weak,alias(sym)))
#if __GNUC__ >= 4
#define DLL_EXPORT __attribute__((visibility("default")))
#define DLL_LOCAL __attribute__((visibility("hidden")))
#define INLINE __attribute__((always_inline))
#else
#define DLL_EXPORT
#define DLL_LOCAL
#define INLINE
#endif
#if __cplusplus >= 201103L && (!__GNUC__ || (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 2)) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#define HAVE_CPP11 1
#if __cplusplus >= 201402
#define HAVE_CPP14 1
#endif
#endif
#if !HAVE_CPP11
#define constexpr
#define override
#define final
#define nullptr NULL
#define noexcept throw()
#endif
#if __GNUC__ >= 3 && (__i386__ || __x86_64__)
/// GCC 3+ supports the prefetch directive, which some CPUs use to improve caching
#define prefetch(p,rw,loc) __builtin_prefetch(p,rw,loc)
#else
#define prefetch(p,rw,loc)
#endif
#if __GNUC__ < 3
/// __alignof__ returns the recommended alignment for the type
#define __alignof__(v) min(sizeof(v), sizeof(void*))
/// This macro returns 1 if the value of x is known at compile time.
#ifndef __builtin_constant_p
#define __builtin_constant_p(x) 0
#endif
#endif
// Define to empty if 'const' does not conform to ANSI C.
#undef const
// Define as '__inline' if that is what the C compiler calls it
#undef inline
// Define to 'long' if <sys/types.h> does not define.
#undef off_t
// Define to 'unsigned' if <sys/types.h> does not define.
#undef size_t
/// gcc has lately decided that inline is just a suggestion
/// Define to 1 if when you say 'inline' you mean it!
#undef WANT_ALWAYS_INLINE
#if WANT_ALWAYS_INLINE
#define inline INLINE inline
#endif
/// Define to 1 if you have the <assert.h> header file.
#undef HAVE_ASSERT_H
/// Define to 1 if you have the <ctype.h> header file.
#undef HAVE_CTYPE_H
/// Define to 1 if you have the <errno.h> header file.
#undef HAVE_ERRNO_H
/// Define to 1 if you have the <fcntl.h> header file.
#undef HAVE_FCNTL_H
/// Define to 1 if you have the <float.h> header file.
#undef HAVE_FLOAT_H
/// Define to 1 if you have the <inttypes.h> header file.
#undef HAVE_INTTYPES_H
/// Define to 1 if you have the <limits.h> header file.
#undef HAVE_LIMITS_H
/// Define to 1 if you have the <locale.h> header file.
#undef HAVE_LOCALE_H
// Define to 1 if you have the <alloca.h> header file.
#undef HAVE_ALLOCA_H
// Define to 1 if you have the <signal.h> header file.
#undef HAVE_SIGNAL_H
// Define to 1 if you have the __va_copy function
#define HAVE_VA_COPY 1
// Define to 1 if you have the <stdarg.h> header file.
#undef HAVE_STDARG_H
// Define to 1 if you have the <stddef.h> header file.
#undef HAVE_STDDEF_H
// Define to 1 if you have the <stdint.h> header file.
#undef HAVE_STDINT_H
// Define to 1 if you have the <stdio.h> header file.
#undef HAVE_STDIO_H
// Define to 1 if you have the <stdlib.h> header file.
#undef HAVE_STDLIB_H
// Define to 1 if you have the <string.h> header file.
#undef HAVE_STRING_H
// Define to 1 if you have the 'strrchr' function.
#define HAVE_STRRCHR 1
// Define to 1 if you have the 'strsignal' function.
#define HAVE_STRSIGNAL 1
// Define to 1 if you have the <sys/stat.h> header file.
#undef HAVE_SYS_STAT_H
// Define to 1 if you have the <sys/types.h> header file.
#undef HAVE_SYS_TYPES_H
// Define to 1 if you have the <sys/mman.h> header file.
#undef HAVE_SYS_MMAN_H
// Define to 1 if you have the <time.h> header file.
#undef HAVE_TIME_H
// Define to 1 if you have the <unistd.h> header file.
#undef HAVE_UNISTD_H
// Define to 1 if you have the <math.h> header file.
#undef HAVE_MATH_H
// Define to 1 if you have the <execinfo.h> header file.
#undef HAVE_EXECINFO_H
// Define to 1 if you have the <cxxabi.h> header file.
#if __GNUC__ >= 3
#define HAVE_CXXABI_H 1
#endif
// Define to 1 if you have the rintf function. Will use rint otherwise.
#undef HAVE_RINTF
// STDC_HEADERS is defined to 1 on sane systems.
#if HAVE_ASSERT_H && HAVE_CTYPE_H && HAVE_ERRNO_H && HAVE_FLOAT_H &&\
HAVE_LIMITS_H && HAVE_LOCALE_H && HAVE_MATH_H && HAVE_SIGNAL_H &&\
HAVE_STDARG_H && HAVE_STDDEF_H && HAVE_STDIO_H && HAVE_STDLIB_H &&\
HAVE_STRING_H && HAVE_TIME_H
#define STDC_HEADERS 1
#endif
// STDC_HEADERS is defined to 1 on unix systems.
#if HAVE_FCNTL_H && HAVE_SYS_STAT_H && HAVE_UNISTD_H
#define STDUNIX_HEADERS 1
#endif
// Define to 1 if your compiler treats char as a separate type along with
// signed char and unsigned char. This will create overloads for char.
#undef HAVE_THREE_CHAR_TYPES
// Define to 1 if you have 64 bit types available
#undef HAVE_INT64_T
// Define to 1 if you have the long long type
#undef HAVE_LONG_LONG
// Define to 1 if you want unrolled specializations for fill and copy
#define WANT_UNROLLED_COPY 1
// Define to 1 if you want to use MMX/SSE/3dNow! processor instructions
#define WANT_MMX 0
// Define to byte sizes of types
#undef SIZE_OF_CHAR
#undef SIZE_OF_SHORT
#undef SIZE_OF_INT
#undef SIZE_OF_LONG
#undef SIZE_OF_LONG_LONG
#undef SIZE_OF_POINTER
#undef SIZE_OF_SIZE_T
#undef SIZE_OF_BOOL
#undef SIZE_T_IS_LONG
// Byte order macros, converted in utypes.h
#define USTL_LITTLE_ENDIAN 4321
#define USTL_BIG_ENDIAN 1234
#define USTL_BYTE_ORDER USTL_LITTLE_ENDIAN
#if __i386__ || __x86_64__
#define __x86__ 1
#endif
// Extended CPU capabilities
#undef CPU_HAS_FPU
#undef CPU_HAS_EXT_DEBUG
#undef CPU_HAS_TIMESTAMPC
#undef CPU_HAS_MSR
#undef CPU_HAS_CMPXCHG8
#undef CPU_HAS_APIC
#undef CPU_HAS_SYSCALL
#undef CPU_HAS_MTRR
#undef CPU_HAS_CMOV
#undef CPU_HAS_FCMOV
#if WANT_MMX
#undef CPU_HAS_MMX
#undef CPU_HAS_FXSAVE
#undef CPU_HAS_SSE
#undef CPU_HAS_SSE2
#undef CPU_HAS_SSE3
#undef CPU_HAS_EXT_3DNOW
#undef CPU_HAS_3DNOW
#endif
// GCC vector extensions
#if (CPU_HAS_MMX || CPU_HAS_SSE) && __GNUC__ >= 3
#undef HAVE_VECTOR_EXTENSIONS
#endif
#if CPU_HAS_SSE && __GNUC__
#define __sse_align __attribute__((aligned(16)))
#else
#define __sse_align
#endif

View File

@ -0,0 +1,62 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "memlink.h"
namespace ustl {
/// \class memblock memblock.h ustl.h
/// \ingroup MemoryManagement
///
/// \brief Allocated memory block.
///
/// Adds memory management capabilities to memlink. Uses malloc and realloc to
/// maintain the internal pointer, but only if allocated using members of this class,
/// or if linked to using the Manage() member function. Managed memory is automatically
/// freed in the destructor.
///
class memblock : public memlink {
public:
memblock (void) noexcept;
memblock (const void* p, size_type n);
explicit memblock (size_type n);
explicit memblock (const cmemlink& b);
explicit memblock (const memlink& b);
memblock (const memblock& b);
virtual ~memblock (void) noexcept;
virtual void unlink (void) noexcept override;
inline void assign (const cmemlink& l) { assign (l.cdata(), l.readable_size()); }
inline const memblock& operator= (const cmemlink& l) { assign (l); return *this; }
inline const memblock& operator= (const memlink& l) { assign (l); return *this; }
inline const memblock& operator= (const memblock& l) { assign (l); return *this; }
inline void swap (memblock& l) noexcept { memlink::swap (l); ::ustl::swap (_capacity, l._capacity); }
void assign (const void* p, size_type n);
void reserve (size_type newSize, bool bExact = false);
void resize (size_type newSize, bool bExact = true);
iterator insert (const_iterator start, size_type size);
iterator erase (const_iterator start, size_type size);
inline void clear (void) noexcept { resize (0); }
inline size_type capacity (void) const { return _capacity; }
inline bool is_linked (void) const { return !capacity(); }
inline size_type max_size (void) const { return is_linked() ? memlink::max_size() : SIZE_MAX; }
inline void manage (memlink& l) { manage (l.begin(), l.size()); }
void deallocate (void) noexcept;
void shrink_to_fit (void);
void manage (void* p, size_type n) noexcept;
void copy_link (void);
void read (istream& is);
void read_file (const char* filename);
#if HAVE_CPP11
inline memblock (memblock&& b) : memlink(), _capacity(0) { swap (b); }
inline memblock& operator= (memblock&& b) { swap (b); return *this; }
#endif
protected:
virtual size_type minimumFreeCapacity (void) const noexcept __attribute__((const));
private:
size_type _capacity; ///< Number of bytes allocated by Resize.
};
} // namespace ustl

View File

@ -0,0 +1,98 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "cmemlink.h"
#include "ualgo.h"
namespace ustl {
/// \class memlink memlink.h ustl.h
/// \ingroup MemoryManagement
///
/// \brief Wrapper for pointer to block with size.
///
/// Use this class the way you would a pointer to an allocated unstructured block.
/// The pointer and block size are available through member functions and cast operator.
///
/// Example usage:
/// \code
/// void* p = malloc (46721);
/// memlink a, b;
/// a.link (p, 46721);
/// assert (a.size() == 46721));
/// b = a;
/// assert (b.size() == 46721));
/// assert (b.begin() + 34 == a.begin + 34);
/// assert (0 == memcmp (a, b, 12));
/// a.fill (673, b, 42, 67);
/// b.erase (87, 12);
/// \endcode
///
class memlink : public cmemlink {
public:
typedef value_type* pointer;
typedef cmemlink::pointer const_pointer;
typedef cmemlink::const_iterator const_iterator;
typedef pointer iterator;
typedef const memlink& rcself_t;
public:
inline memlink (void) : cmemlink() {}
inline memlink (void* p, size_type n) : cmemlink (p, n) {}
inline memlink (const void* p, size_type n) : cmemlink (p, n) {}
inline memlink (rcself_t l) : cmemlink (l) {}
inline explicit memlink (const cmemlink& l) : cmemlink (l) {}
inline pointer data (void) { return const_cast<pointer>(cmemlink::data()); }
inline const_pointer data (void) const { return cmemlink::data(); }
inline iterator begin (void) { return iterator (data()); }
inline iterator iat (size_type i) { assert (i <= size()); return begin() + i; }
inline iterator end (void) { return iat (size()); }
inline const_iterator begin (void) const { return cmemlink::begin(); }
inline const_iterator end (void) const { return cmemlink::end(); }
inline const_iterator iat (size_type i) const { return cmemlink::iat (i); }
size_type writable_size (void) const { return size(); }
inline rcself_t operator= (const cmemlink& l) { cmemlink::operator= (l); return *this; }
inline rcself_t operator= (rcself_t l) { cmemlink::operator= (l); return *this; }
inline void link (const void* p, size_type n) { cmemlink::link (p, n); }
inline void link (void* p, size_type n) { cmemlink::link (p, n); }
inline void link (const cmemlink& l) { cmemlink::link (l); }
inline void link (memlink& l) { cmemlink::link (l); }
inline void link (const void* first, const void* last) { link (first, distance (first, last)); }
inline void link (void* first, void* last) { link (first, distance (first, last)); }
inline void relink (const void* p, size_type n) { cmemlink::relink (p, n); }
inline void relink (void* p, size_type n) { cmemlink::relink (p, n); }
inline void swap (memlink& l) { cmemlink::swap (l); }
void fill (const_iterator start, const void* p, size_type elsize, size_type elCount = 1) noexcept;
inline void insert (const_iterator start, size_type size);
inline void erase (const_iterator start, size_type size);
void read (istream& is);
};
/// Shifts the data in the linked block from \p start to \p start + \p n.
/// The contents of the uncovered bytes is undefined.
inline void memlink::insert (const_iterator cstart, size_type n)
{
assert (data() || !n);
assert (cmemlink::begin() || !n);
assert (cstart >= begin() && cstart + n <= end());
iterator start = const_cast<iterator>(cstart);
rotate (start, end() - n, end());
}
/// Shifts the data in the linked block from \p start + \p n to \p start.
/// The contents of the uncovered bytes is undefined.
inline void memlink::erase (const_iterator cstart, size_type n)
{
assert (data() || !n);
assert (cmemlink::begin() || !n);
assert (cstart >= begin() && cstart + n <= end());
iterator start = const_cast<iterator>(cstart);
rotate (start, start + n, end());
}
/// Use with memlink-derived classes to allocate and link to stack space.
#define alloca_link(m,n) (m).link (alloca (n), (n))
} // namespace ustl

View File

@ -0,0 +1,89 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//
/// \file metamac.h
/// \brief Macros for complex metaprogramming involving pseudoiteration.
#pragma once
//----------------------------------------------------------------------
// Functors and general utilities.
//----------------------------------------------------------------------
/// Evaluates to itself
#define ITSELF(x) x
/// Concatenates \p a and \p b
#define PASTE(a,b) a##b
//----------------------------------------------------------------------
// Lists and other iterators
//----------------------------------------------------------------------
/// The maximum number of elements in REPEAT, LIST, and COMMA_LIST
#define METAMAC_MAXN 9
/// Simple list with no separators. Repeats x N times.
/// @{
#define REPEAT_1(x) x(1)
#define REPEAT_2(x) REPEAT_1(x) x(2)
#define REPEAT_3(x) REPEAT_2(x) x(3)
#define REPEAT_4(x) REPEAT_3(x) x(4)
#define REPEAT_5(x) REPEAT_4(x) x(5)
#define REPEAT_6(x) REPEAT_5(x) x(6)
#define REPEAT_7(x) REPEAT_6(x) x(7)
#define REPEAT_8(x) REPEAT_7(x) x(8)
#define REPEAT_9(x) REPEAT_8(x) x(9)
#define REPEAT(N,x) PASTE(REPEAT_,N)(x)
/// @}
/// Simple separated list. Repeats x N times with sep in between.
/// @{
#define LIST_1(x,sep) x(1)
#define LIST_2(x,sep) LIST_1(x,sep) sep x(2)
#define LIST_3(x,sep) LIST_2(x,sep) sep x(3)
#define LIST_4(x,sep) LIST_3(x,sep) sep x(4)
#define LIST_5(x,sep) LIST_4(x,sep) sep x(5)
#define LIST_6(x,sep) LIST_5(x,sep) sep x(6)
#define LIST_7(x,sep) LIST_6(x,sep) sep x(7)
#define LIST_8(x,sep) LIST_7(x,sep) sep x(8)
#define LIST_9(x,sep) LIST_8(x,sep) sep x(9)
#define LIST(N,x,sep) PASTE(LIST_,N)(x,sep)
/// @}
/// Comma separated list. A special case of LIST needed because the preprocessor can't substitute commas.
/// @{
#define COMMA_LIST_1(x) x(1)
#define COMMA_LIST_2(x) COMMA_LIST_1(x), x(2)
#define COMMA_LIST_3(x) COMMA_LIST_2(x), x(3)
#define COMMA_LIST_4(x) COMMA_LIST_3(x), x(4)
#define COMMA_LIST_5(x) COMMA_LIST_4(x), x(5)
#define COMMA_LIST_6(x) COMMA_LIST_5(x), x(6)
#define COMMA_LIST_7(x) COMMA_LIST_6(x), x(7)
#define COMMA_LIST_8(x) COMMA_LIST_7(x), x(8)
#define COMMA_LIST_9(x) COMMA_LIST_8(x), x(9)
#define COMMA_LIST(N,x) PASTE(COMMA_LIST_,N)(x)
/// @}
//----------------------------------------------------------------------
// Macros for defining LIST arguments.
//----------------------------------------------------------------------
/// Ignores N, producing lists of identically named arguments.
#define LARG_NONE(name,N) name
/// Appends N to name.
#define LARG_NUMBER(name,N) name##N
/// name is a reference type.
#define LARG_REF(name,N) name##N&
/// Sequential parameter passed by value with sequential types.
#define LARG_MT_PARAM_BY_VALUE(type,name,N) type##N name##N
/// Sequential parameter passed by reference with sequential types.
#define LARG_MT_PARAM_BY_REF(type,name,N) type##N& name##N
//----------------------------------------------------------------------

View File

@ -0,0 +1,295 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "memlink.h"
#include "strmsize.h"
#include "utf8.h"
#include "uios.h"
#if WANT_STREAM_BOUNDS_CHECKING
#include "typeinfo.h"
#endif
namespace ustl {
class ostream;
class memlink;
class string;
/// \class istream mistream.h ustl.h
/// \ingroup BinaryStreams
///
/// \brief Helper class to read packed binary streams.
///
/// This class contains a set of functions to read integral types from an
/// unstructured memory block. Unpacking binary file data can be done this
/// way, for instance. aligning the data is your responsibility, and can
/// be accomplished by proper ordering of reads and by calling the align()
/// function. Unaligned access is usually slower by orders of magnitude and,
/// on some architectures, such as PowerPC, can cause your program to crash.
/// Therefore, all read functions have asserts to check alignment.
/// Overreading the end of the stream will also cause a crash (an assert in
/// debug builds). Oh, and don't be intimidated by the size of the inlines
/// here. In the assembly code the compiler will usually chop everything down
/// to five instructions each.
///
/// Alignment rules for your objects:
/// - Assume your writes start off 4-byte aligned.
/// - After completion, \ref istream::align the stream to at least 4.
/// - If data portability between 32bit and 64bit platforms is important
/// (it often is not, in config files and the like), ensure you are always
/// using fixed-size types and are aligning to a fixed grain. Avoid writing
/// 8-byte types, and if you do, manually align before doing so.
/// - Non-default alignment is allowed if you plan to frequently write this
/// object in array form and alignment would be costly. For example, an
/// array of uint16_t-sized objects may leave the stream uint16_t aligned
/// as long as you know about it and will default-align the stream after
/// writing the array (note: \ref vector will already do this for you)
///
/// Example code:
/// \code
/// memblock b;
/// b.read_file ("test.file");
/// ostream is (b);
/// is >> boolVar >> ios::talign<int>();
/// is >> intVar >> floatVar;
/// is.read (binaryData, binaryDataSize);
/// is.align();
/// \endcode
///
class istream : public cmemlink, public ios_base {
public:
inline istream (void) : cmemlink(), _pos (0) {}
inline istream (const void* p, streamsize n) : cmemlink(p, n), _pos (0) {}
inline explicit istream (const cmemlink& source) : cmemlink (source), _pos (0) {}
explicit istream (const ostream& source) noexcept;
inline iterator end (void) const { return cmemlink::end(); }
inline void link (const void* p, streamsize n) { cmemlink::link (p, n); }
inline void link (const cmemlink& l) { cmemlink::link (l.cdata(), l.readable_size()); }
inline void link (const void* f, const void* l) { cmemlink::link (f, l); }
inline void relink (const void* p, streamsize n) { cmemlink::relink (p, n); _pos = 0; }
inline void relink (const cmemlink& l) { relink (l.cdata(), l.readable_size()); }
virtual void unlink (void) noexcept override;
virtual streamsize underflow (streamsize = 1);
inline uoff_t pos (void) const { return _pos; }
inline const_iterator ipos (void) const { return begin() + pos(); }
inline streamsize remaining (void) const { return size() - pos(); }
inline void seek (uoff_t newPos);
inline void iseek (const_iterator newPos);
inline void skip (streamsize nBytes);
inline bool aligned (streamsize grain = c_DefaultAlignment) const;
inline bool verify_remaining (const char* op, const char* type, streamsize n);
inline streamsize align_size (streamsize grain = c_DefaultAlignment) const;
inline void align (streamsize grain = c_DefaultAlignment);
inline void swap (istream& is);
inline void read (void* buffer, streamsize size);
inline void read (memlink& buf) { read (buf.begin(), buf.writable_size()); }
void read_strz (string& str);
streamsize readsome (void* s, streamsize n);
inline void read (istream&) { }
void write (ostream& os) const;
void text_write (ostringstream& os) const;
inline streamsize stream_size (void) const { return remaining(); }
template <typename T>
inline void iread (T& v);
inline void ungetc (void) { seek (pos() - 1); }
inline off_t tellg (void) const { return pos(); }
inline void seekg (off_t p, seekdir d = beg);
private:
streamoff _pos; ///< The current read position.
};
//----------------------------------------------------------------------
template <typename T, typename Stream>
inline streamsize required_stream_size (T, const Stream&) { return 1; }
template <typename T>
inline streamsize required_stream_size (T v, const istream&) { return stream_size_of(v); }
template <typename Stream>
inline bool stream_at_eof (const Stream& stm) { return stm.eof(); }
template <>
inline bool stream_at_eof (const istream&) { return false; }
/// \class istream_iterator
/// \ingroup BinaryStreamIterators
///
/// \brief An iterator over an istream to use with uSTL algorithms.
///
template <typename T, typename Stream = istream>
class istream_iterator {
public:
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const value_type* pointer;
typedef const value_type& reference;
typedef typename Stream::size_type size_type;
typedef input_iterator_tag iterator_category;
public:
istream_iterator (void) : _pis (nullptr), _v() {}
explicit istream_iterator (Stream& is) : _pis (&is), _v() { Read(); }
istream_iterator (const istream_iterator& i) : _pis (i._pis), _v (i._v) {}
/// Reads and returns the next value.
inline const T& operator* (void) { return _v; }
inline istream_iterator& operator++ (void) { Read(); return *this; }
inline istream_iterator& operator-- (void) { _pis->seek (_pis->pos() - 2 * stream_size_of(_v)); return operator++(); }
inline istream_iterator operator++ (int) { istream_iterator old (*this); operator++(); return old; }
inline istream_iterator operator-- (int) { istream_iterator old (*this); operator--(); return old; }
inline istream_iterator& operator+= (streamsize n) { while (n--) operator++(); return *this; }
inline istream_iterator& operator-= (streamsize n) { _pis->seek (_pis->pos() - (n + 1) * stream_size_of(_v)); return operator++(); }
inline istream_iterator operator- (streamoff n) const { istream_iterator result (*this); return result -= n; }
inline difference_type operator- (const istream_iterator& i) const { return distance (i._pis->pos(), _pis->pos()) / stream_size_of(_v); }
inline bool operator== (const istream_iterator& i) const { return (!_pis && !i._pis) || (_pis && i._pis && _pis->pos() == i._pis->pos()); }
inline bool operator< (const istream_iterator& i) const { return !i._pis || (_pis && _pis->pos() < i._pis->pos()); }
private:
void Read (void)
{
if (!_pis)
return;
const streamsize rs (required_stream_size (_v, *_pis));
if (_pis->remaining() < rs && _pis->underflow (rs) < rs) {
_pis = nullptr;
return;
}
*_pis >> _v;
if (stream_at_eof (*_pis))
_pis = nullptr;
}
private:
Stream* _pis; ///< The host stream.
T _v; ///< Last read value; cached to be returnable as a const reference.
};
//----------------------------------------------------------------------
/// Checks that \p n bytes are available in the stream, or else throws.
inline bool istream::verify_remaining (const char* op, const char* type, streamsize n)
{
const streamsize rem = remaining();
bool enough = n <= rem;
if (!enough) overrun (op, type, n, pos(), rem);
return enough;
}
/// Sets the current read position to \p newPos
inline void istream::seek (uoff_t newPos)
{
#if WANT_STREAM_BOUNDS_CHECKING
if (newPos > size())
return overrun ("seekg", "byte", newPos, pos(), size());
#else
assert (newPos <= size());
#endif
_pos = newPos;
}
/// Sets the current read position to \p newPos
inline void istream::iseek (const_iterator newPos)
{
seek (distance (begin(), newPos));
}
/// Sets the current write position to \p p based on \p d.
inline void istream::seekg (off_t p, seekdir d)
{
switch (d) {
case beg: seek (p); break;
case cur: seek (pos() + p); break;
case ios_base::end: seek (size() - p); break;
}
}
/// Skips \p nBytes without reading them.
inline void istream::skip (streamsize nBytes)
{
seek (pos() + nBytes);
}
/// Returns the number of bytes to skip to be aligned on \p grain.
inline streamsize istream::align_size (streamsize grain) const
{
return Align (pos(), grain) - pos();
}
/// Returns \c true if the read position is aligned on \p grain
inline bool istream::aligned (streamsize grain) const
{
return pos() % grain == 0;
}
/// aligns the read position on \p grain
inline void istream::align (streamsize grain)
{
seek (Align (pos(), grain));
}
/// Reads type T from the stream via a direct pointer cast.
template <typename T>
inline void istream::iread (T& v)
{
assert (aligned (stream_align_of (v)));
#if WANT_STREAM_BOUNDS_CHECKING
if (!verify_remaining ("read", typeid(v).name(), sizeof(T)))
return;
#else
assert (remaining() >= sizeof(T));
#endif
v = *reinterpret_cast<const T*>(ipos());
_pos += sizeof(T);
}
/// Swaps contents with \p is
inline void istream::swap (istream& is)
{
cmemlink::swap (is);
::ustl::swap (_pos, is._pos);
}
/// Reads \p n bytes into \p buffer.
inline void istream::read (void* buffer, size_type n)
{
#if WANT_STREAM_BOUNDS_CHECKING
if (!verify_remaining ("read", "binary data", n))
return;
#else
assert (remaining() >= n && "Reading past end of buffer. Make sure you are reading the right format.");
#endif
memcpy (reinterpret_cast<value_type*>(buffer), ipos(), n);
_pos += n;
}
//----------------------------------------------------------------------
template <typename T> struct object_reader {
inline void operator()(istream& is, T& v) const { v.read (is); }
};
template <typename T> struct integral_object_reader {
inline void operator()(istream& is, T& v) const { is.iread (v); }
};
template <typename T>
inline istream& operator>> (istream& is, T& v) {
typedef typename tm::Select <numeric_limits<T>::is_integral,
integral_object_reader<T>, object_reader<T> >::Result object_reader_t;
object_reader_t()(is, v);
return is;
}
template <typename T>
inline istream& operator>> (istream& is, const T& v) { v.read (is); return is; }
//----------------------------------------------------------------------
typedef istream_iterator<utf8subchar_t> istream_iterator_for_utf8;
typedef utf8in_iterator<istream_iterator_for_utf8> utf8istream_iterator;
/// Returns a UTF-8 adaptor reading from \p is.
inline utf8istream_iterator utf8in (istream& is)
{
istream_iterator_for_utf8 si (is);
return utf8istream_iterator (si);
}
//----------------------------------------------------------------------
} // namespace ustl

View File

@ -0,0 +1,266 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "memlink.h"
#include "utf8.h"
#include "uios.h"
#include "strmsize.h"
#if WANT_STREAM_BOUNDS_CHECKING
#include "typeinfo.h"
#endif
namespace ustl {
class istream;
class string;
/// \class ostream mostream.h ustl.h
/// \ingroup BinaryStreams
///
/// \brief Helper class to write packed binary streams.
///
/// This class contains a set of functions to write integral types into an
/// unstructured memory block. Packing binary file data can be done this
/// way, for instance. aligning the data is your responsibility, and can
/// be accomplished by proper ordering of writes and by calling align.
/// Unaligned access is usually slower by orders of magnitude and,
/// on some architectures, such as PowerPC, can cause your program to crash.
/// Therefore, all write functions have asserts to check alignment.
/// See \ref istream documentation for rules on designing your data format.
/// Overwriting the end of the stream will also cause a crash (an assert in
/// debug builds). Oh, and don't be intimidated by the size of the inlines
/// here. In the assembly code the compiler will usually chop everything down
/// to five instructions each.
///
/// Example code:
/// \code
/// memblock b;
/// ostream os (b);
/// os << boolVar << ios::talign<int>();
/// os << intVar << floatVar;
/// os.write (binaryData, binaryDataSize);
/// os.align();
/// b.resize (os.pos());
/// b.write_file ("test.file");
/// \endcode
///
class ostream : public memlink, public ios_base {
public:
inline ostream (void) : memlink(), _pos(0) {}
inline ostream (void* p, streamsize n) : memlink (p, n), _pos (0) {}
inline explicit ostream (const memlink& source) : memlink (source), _pos (0) {}
inline iterator end (void) { return memlink::end(); }
inline const_iterator end (void) const { return memlink::end(); }
inline void seek (uoff_t newPos);
inline void iseek (const_iterator newPos);
inline void skip (streamsize nBytes);
inline uoff_t pos (void) const { return _pos; }
inline iterator ipos (void) { return begin() + pos(); }
inline const_iterator ipos (void) const { return begin() + pos(); }
inline streamsize remaining (void) const;
inline bool aligned (streamsize grain = c_DefaultAlignment) const;
bool verify_remaining (const char* op, const char* type, size_t n);
inline streamsize align_size (streamsize grain = c_DefaultAlignment) const;
void align (streamsize grain = c_DefaultAlignment);
inline void write (const void* buffer, streamsize size);
inline void write (const cmemlink& buf);
void write_strz (const char* str);
void read (istream& is);
inline void write (ostream& os) const { os.write (begin(), pos()); }
void text_write (ostringstream& os) const;
inline size_t stream_size (void) const { return pos(); }
void insert (iterator start, streamsize size);
void erase (iterator start, streamsize size);
inline void swap (ostream& os);
template <typename T>
inline void iwrite (const T& v);
inline virtual ostream& flush (void) { return *this; }
inline virtual streamsize overflow (streamsize=1) { return remaining(); }
virtual void unlink (void) noexcept override;
inline void link (void* p, streamsize n) { memlink::link (p, n); }
inline void link (memlink& l) { memlink::link (l.data(), l.writable_size()); }
inline void link (void* f, void* l) { memlink::link (f, l); }
inline void relink (void* p, streamsize n) { memlink::relink (p, n); _pos = 0; }
inline void relink (memlink& l) { relink (l.data(), l.writable_size()); }
inline void seekp (off_t p, seekdir d = beg);
inline off_t tellp (void) const { return pos(); }
protected:
inline void SetPos (uoff_t newPos) { _pos = newPos; }
private:
streamoff _pos; ///< Current write position.
};
//----------------------------------------------------------------------
/// \class ostream_iterator mostream.h ustl.h
/// \ingroup BinaryStreamIterators
///
/// \brief An iterator over an ostream to use with uSTL algorithms.
///
template <typename T, typename Stream = ostream>
class ostream_iterator {
public:
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef value_type* pointer;
typedef value_type& reference;
typedef typename Stream::size_type size_type;
typedef output_iterator_tag iterator_category;
public:
inline explicit ostream_iterator (Stream& os)
: _os (os) {}
inline ostream_iterator (const ostream_iterator& iter)
: _os (iter._os) {}
/// Writes \p v into the stream.
inline ostream_iterator& operator= (const T& v)
{ _os << v; return *this; }
inline ostream_iterator& operator* (void) { return *this; }
inline ostream_iterator& operator++ (void) { return *this; }
inline ostream_iterator operator++ (int) { return *this; }
inline ostream_iterator& operator+= (streamsize n) { _os.skip (n); return *this; }
inline bool operator== (const ostream_iterator& i) const
{ return _os.pos() == i._os.pos(); }
inline bool operator< (const ostream_iterator& i) const
{ return _os.pos() < i._os.pos(); }
private:
Stream& _os;
};
//----------------------------------------------------------------------
typedef ostream_iterator<utf8subchar_t> ostream_iterator_for_utf8;
typedef utf8out_iterator<ostream_iterator_for_utf8> utf8ostream_iterator;
/// Returns a UTF-8 adaptor writing to \p os.
inline utf8ostream_iterator utf8out (ostream& os)
{
ostream_iterator_for_utf8 si (os);
return utf8ostream_iterator (si);
}
//----------------------------------------------------------------------
/// Checks that \p n bytes are available in the stream, or else throws.
inline bool ostream::verify_remaining (const char* op, const char* type, size_t n)
{
const size_t rem = remaining();
bool enough = n <= rem;
if (!enough) overrun (op, type, n, pos(), rem);
return enough;
}
/// Move the write pointer to \p newPos
inline void ostream::seek (uoff_t newPos)
{
#if WANT_STREAM_BOUNDS_CHECKING
if (newPos > size())
return overrun ("seekp", "byte", newPos, pos(), size());
#else
assert (newPos <= size());
#endif
SetPos (newPos);
}
/// Sets the current write position to \p newPos
inline void ostream::iseek (const_iterator newPos)
{
seek (distance (begin(), const_cast<iterator>(newPos)));
}
/// Sets the current write position to \p p based on \p d.
inline void ostream::seekp (off_t p, seekdir d)
{
switch (d) {
case beg: seek (p); break;
case cur: seek (pos() + p); break;
case ios_base::end: seek (size() - p); break;
}
}
/// Skips \p nBytes without writing anything.
inline void ostream::skip (streamsize nBytes)
{
seek (pos() + nBytes);
}
/// Returns number of bytes remaining in the write buffer.
inline streamsize ostream::remaining (void) const
{
return size() - pos();
}
/// Returns \c true if the write pointer is aligned on \p grain
inline bool ostream::aligned (streamsize grain) const
{
return pos() % grain == 0;
}
/// Returns the number of bytes to skip to be aligned on \p grain.
inline streamsize ostream::align_size (streamsize grain) const
{
return Align (pos(), grain) - pos();
}
/// Writes \p n bytes from \p buffer.
inline void ostream::write (const void* buffer, size_type n)
{
#if WANT_STREAM_BOUNDS_CHECKING
if (!verify_remaining ("write", "binary data", n))
return;
#else
assert (remaining() >= n && "Buffer overrun. Check your stream size calculations.");
#endif
memcpy (ipos(), const_iterator(buffer), n);
_pos += n;
}
/// Writes the contents of \p buf into the stream as a raw dump.
inline void ostream::write (const cmemlink& buf)
{
write (buf.begin(), buf.size());
}
/// Writes type T into the stream via a direct pointer cast.
template <typename T>
inline void ostream::iwrite (const T& v)
{
assert (aligned (stream_align_of (v)));
#if WANT_STREAM_BOUNDS_CHECKING
if (!verify_remaining ("write", typeid(v).name(), sizeof(T)))
return;
#else
assert (remaining() >= sizeof(T));
#endif
*reinterpret_cast<T*>(ipos()) = v;
SetPos (pos() + sizeof(T));
}
/// Swaps with \p os
inline void ostream::swap (ostream& os)
{
memlink::swap (os);
::ustl::swap (_pos, os._pos);
}
//----------------------------------------------------------------------
template <typename T> struct object_writer {
inline void operator()(ostream& os, const T& v) const { v.write (os); }
};
template <typename T> struct integral_object_writer {
inline void operator()(ostream& os, const T& v) const { os.iwrite (v); }
};
template <typename T>
inline ostream& operator<< (ostream& os, const T& v) {
typedef typename tm::Select <numeric_limits<T>::is_integral,
integral_object_writer<T>, object_writer<T> >::Result object_writer_t;
object_writer_t()(os, v);
return os;
}
//----------------------------------------------------------------------
} // namespace ustl

View File

@ -0,0 +1,135 @@
#pragma once
#include "sostream.h"
#include "kprintf.h"
#include "uios.h"
namespace ustl {
/// \class coutclass sostream.h ustl.h
/// \ingroup TextStreams
///
/// \brief This stream writes textual data into a memory block.
///
class coutclass : public ostream {
public:
static void init();
coutclass();
coutclass(void* p, size_t n);
coutclass(void(*m_kprintf)(const char*, ...));
coutclass(void* p, size_t n, void(*m_kprintf)(const char*, ...));
void iwrite (uint8_t v);
void iwrite (wchar_t v);
inline void iwrite (int v) { iformat (v); }
inline void iwrite (unsigned int v) { iformat (v); }
inline void iwrite (long int v) { iformat (v); }
inline void iwrite (unsigned long int v) { iformat (v); }
void iwrite (bool v);
inline void iwrite (const char* s) { write (s, strlen(s)); }
inline void iwrite (const string& v) { write (v.begin(), v.size()); }
inline void iwrite (fmtflags f);
#if HAVE_LONG_LONG
inline void iwrite (long long v) { iformat (v); }
inline void iwrite (unsigned long long v) { iformat (v); }
#endif
inline size_type max_size (void) const { return 0; }
inline coutclass& put (char c) { iwrite (uint8_t(c)); return (*this); }
int format (const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
inline void set_base (uint16_t b) { m_Base = b; }
inline void set_width (uint16_t w) { m_Width = w; }
inline void set_decimal_separator (char) { }
inline void set_thousand_separator (char) { }
inline void set_precision (uint16_t v) { m_Precision = v; }
void link (void* p, size_type n);
inline void link (memlink& l) { link (l.data(), l.writable_size()); }
void str (const string& s);
coutclass& write (const void* buffer, size_type size);
inline coutclass& write (const cmemlink& buf) { return (write (buf.begin(), buf.size())); }
inline coutclass& seekp (off_t p __attribute__((unused)), __attribute__((unused)) seekdir d =beg) { return (*this); }
coutclass& flush (void) { return (*this); }
virtual size_type overflow (size_type n = 1);
protected:
inline void reserve (__attribute__((unused)) size_type n) { }
inline size_type capacity (void) const { return 0; }
private:
inline void write_strz (const char*) { assert (!"Writing nul characters into a text stream is not allowed"); }
inline char* encode_dec (char* fmt, uint32_t n) const;
void fmtstring (char* fmt, const char* typestr, bool bInteger) const;
template <typename T>
void iformat (T v);
private:
uint32_t m_Flags; ///< See ios_base::fmtflags.
uint16_t m_Width; ///< Field width.
uint8_t m_Base; ///< Numeric base for writing numbers.
uint8_t m_Precision; ///< Number of digits after the decimal separator.
void (*m_kprintf)(const char*, ...);
};
//----------------------------------------------------------------------
template <typename T>
void coutclass::iformat (T v)
{
char fmt [16];
fmtstring (fmt, printf_typestring(v), numeric_limits<T>::is_integer);
kprintf(fmt, v);
}
/// Sets the flag \p f in the stream.
inline void coutclass::iwrite (fmtflags f)
{
switch (f.f) {
case oct: set_base (8); break;
case dec: set_base (10); break;
case hex: set_base (16); break;
case left: m_Flags |= left; m_Flags &= ~right; break;
case right: m_Flags |= right; m_Flags &= ~left; break;
default: m_Flags |= f.f; break;
}
}
//----------------------------------------------------------------------
template <typename T> struct object_text_writer_cout {
inline void operator()(coutclass& os, const T& v) const { v.text_write (os); }
};
template <typename T> struct integral_text_object_writer_cout {
inline void operator()(coutclass& os, const T& v) const { os.iwrite (v); }
};
template <typename T>
inline coutclass& operator<< (coutclass& os, const T& v) {
typedef typename tm::Select <numeric_limits<T>::is_integral,
integral_text_object_writer_cout<T>, object_text_writer_cout<T> >::Result object_writer_t;
object_writer_t()(os, v);
return (os);
}
// Needed because if called with a char[], numeric_limits will not work. Should be removed if I find out how to partial specialize for arrays...
inline coutclass& operator<< (coutclass& os, const char* v)
{ os.iwrite (v); return (os); }
inline coutclass& operator<< (coutclass& os, char* v)
{ os.iwrite (v); return (os); }
//----------------------------------------------------------------------
template <> struct object_text_writer_cout<string> {
inline void operator()(coutclass& os, const string& v) const { os.iwrite (v); }
};
template <typename T> struct integral_text_object_writer_cout<T*> {
inline void operator() (coutclass& os, const T* const& v) const
{ os.iwrite ((uintptr_t)(v)); }
};
#define COUTCLASS_CAST_OPERATOR(RealT, CastT) \
template <> inline coutclass& operator<< (coutclass& os, const RealT& v) \
{ os.iwrite ((CastT)(v)); return (os); }
COUTCLASS_CAST_OPERATOR (uint8_t* const, const char*)
COUTCLASS_CAST_OPERATOR (int8_t, uint8_t)
COUTCLASS_CAST_OPERATOR (short int, int)
COUTCLASS_CAST_OPERATOR (unsigned short, unsigned int)
#if HAVE_THREE_CHAR_TYPES
COUTCLASS_CAST_OPERATOR (char, uint8_t)
#endif
#undef COUTCLASS_CAST_OPERATOR
};

View File

@ -0,0 +1,132 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "mistream.h"
#include "ustring.h"
#ifndef EOF
#define EOF (-1)
#endif
namespace ustl {
/// \class istringstream sistream.h ustl.h
/// \ingroup TextStreams
///
/// \brief A stream that reads textual data from a memory block.
///
class istringstream : public istream {
public:
static const size_type c_MaxDelimiters = 16; ///< Maximum number of word delimiters.
public:
istringstream (void) noexcept;
istringstream (const void* p, size_type n) noexcept;
explicit istringstream (const cmemlink& source) noexcept;
inline fmtflags flags (void) const { return _flags; }
inline fmtflags flags (fmtflags f) { fmtflags of (_flags); _flags.f = f.f; return of; }
inline fmtflags setf (fmtflags f) { fmtflags of (_flags); _flags.f |= f.f; return of; }
inline fmtflags unsetf (fmtflags f) { fmtflags of (_flags); _flags.f &= ~f.f; return of; }
inline fmtflags setf (fmtflags f, fmtflags m) { unsetf(m); return setf(f); }
inline void iread (char& v) { v = skip_delimiters(); }
inline void iread (unsigned char& v) { char c; iread(c); v = c; }
void iread (int& v);
inline void iread (unsigned int& v) { int c; iread(c); v = c; }
inline void iread (short& v) { int c; iread(c); v = c; }
inline void iread (unsigned short& v) { int c; iread(c); v = c; }
void iread (long& v);
inline void iread (unsigned long& v) { long c; iread(c); v = c; }
#if HAVE_THREE_CHAR_TYPES
void iread (signed char& v) { char c; iread(c); v = c; }
#endif
#if HAVE_LONG_LONG
void iread (long long& v);
inline void iread (unsigned long long& v) { long long c; iread(c); v = c; }
#endif
/*inline void iread (float& v) { double c; iread(c); v = c; }
inline void iread (long double& v) { double c; iread(c); v = c; }*/
inline void iread (fmtflags_bits f);
/*void iread (double& v);
inline void iread (float& v) { double c; iread(c); v = c; }
inline void iread (long double& v) { double c; iread(c); v = c; }*/
void iread (bool& v);
void iread (wchar_t& v);
void iread (string& v);
inline string str (void) const { string s; s.link (*this); return s; }
inline istringstream& str (const string& s) { link (s); return *this; }
inline istringstream& get (char& c) { return read (&c, sizeof(c)); }
inline int get (void) { char c = EOF; get(c); return c; }
istringstream& get (char* p, size_type n, char delim = '\n');
istringstream& get (string& s, char delim = '\n');
istringstream& getline (char* p, size_type n, char delim = '\n');
istringstream& getline (string& s, char delim = '\n');
istringstream& ignore (size_type n, char delim = '\0');
inline char peek (void) { char v = get(); ungetc(); return v; }
inline istringstream& unget (void) { ungetc(); return *this; }
inline void set_delimiters (const char* delimiters);
istringstream& read (void* buffer, size_type size);
inline istringstream& read (memlink& buf) { return read (buf.begin(), buf.size()); }
inline size_type gcount (void) const { return _gcount; }
inline istringstream& seekg (off_t p, seekdir d =beg) { istream::seekg(p,d); return *this; }
inline int sync (void) { skip (remaining()); return 0; }
protected:
char skip_delimiters (void);
private:
inline void read_strz (string&) { assert (!"Reading nul characters is not allowed from text streams"); }
inline bool is_delimiter (char c) const noexcept;
template <typename T> void read_number (T& v);
private:
fmtflags _flags;
uint32_t _gcount;
char _delimiters [c_MaxDelimiters];
};
//----------------------------------------------------------------------
void istringstream::iread (fmtflags_bits f)
{
if (f & basefield) setf (f, basefield);
else if (f & floatfield) setf (f, floatfield);
else if (f & adjustfield) setf (f, adjustfield);
setf (f);
}
/// Sets delimiters to the contents of \p delimiters.
void istringstream::set_delimiters (const char* delimiters)
{
#if __x86__ && __SSE__ && HAVE_VECTOR_EXTENSIONS
typedef uint32_t v16ud_t __attribute__((vector_size(16)));
asm("xorps\t%%xmm0, %%xmm0\n\tmovups\t%%xmm0, %0":"=m"(*noalias_cast<v16ud_t*>(_delimiters))::"xmm0");
#else
memset (_delimiters, 0, sizeof(_delimiters));
#endif
memcpy (_delimiters, delimiters, min (strlen(delimiters),sizeof(_delimiters)-1));
}
/// Reads a line of text from \p is into \p s
inline istringstream& getline (istringstream& is, string& s, char delim = '\n')
{ return is.getline (s, delim); }
//----------------------------------------------------------------------
template <typename T> struct object_text_reader {
inline void operator()(istringstream& is, T& v) const { v.text_read (is); }
};
template <typename T> struct integral_text_object_reader {
inline void operator()(istringstream& is, T& v) const { is.iread (v); }
};
template <typename T>
inline istringstream& operator>> (istringstream& is, T& v) {
typedef typename tm::Select <numeric_limits<T>::is_integral,
integral_text_object_reader<T>, object_text_reader<T> >::Result object_reader_t;
object_reader_t()(is, v);
return is;
}
//----------------------------------------------------------------------
template <> struct object_text_reader<string> {
inline void operator()(istringstream& is, string& v) const { is.iread (v); }
};
} // namespace ustl

View File

@ -0,0 +1,213 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "ustring.h"
#include "mostream.h"
namespace ustl {
class string;
/// \class ostringstream sostream.h ustl.h
/// \ingroup TextStreams
///
/// \brief This stream writes textual data into a memory block.
///
class ostringstream : public ostream {
public:
ostringstream (const string& v = "");
ostringstream (void* p, size_t n) noexcept;
inline fmtflags flags (void) const { return _flags; }
inline fmtflags flags (fmtflags f) { fmtflags of (_flags); _flags.f = f.f; return of; }
inline fmtflags setf (fmtflags f) { fmtflags of (_flags); _flags.f |= f.f; return of; }
inline fmtflags unsetf (fmtflags f) { fmtflags of (_flags); _flags.f &= ~f.f; return of; }
inline fmtflags setf (fmtflags f, fmtflags m) { unsetf(m); return setf(f); }
void iwrite (unsigned char v);
void iwrite (wchar_t v);
inline void iwrite (char v) { iwrite (static_cast<unsigned char>(v)); }
inline void iwrite (short v) { iformat (v); }
inline void iwrite (unsigned short v) { iformat (v); }
inline void iwrite (int v) { iformat (v); }
inline void iwrite (unsigned int v) { iformat (v); }
inline void iwrite (long int v) { iformat (v); }
inline void iwrite (unsigned long int v) { iformat (v); }
/*inline void iwrite (float v) { iformat (v); }
inline void iwrite (double v) { iformat (v); }
inline void iwrite (long double v) { iformat (v); }*/
void iwrite (bool v);
inline void iwrite (const char* s) { write (s, strlen(s)); }
inline void iwrite (const unsigned char* s) { iwrite (reinterpret_cast<const char*>(s)); }
inline void iwrite (const string& v) { write (v.begin(), v.size()); }
inline void iwrite (fmtflags_bits f);
#if HAVE_THREE_CHAR_TYPES
inline void iwrite (signed char v) { iwrite (static_cast<char>(v)); }
#endif
#if HAVE_LONG_LONG
inline void iwrite (long long v) { iformat (v); }
inline void iwrite (unsigned long long v) { iformat (v); }
#endif
inline size_type max_size (void) const { return _buffer.max_size(); }
inline ostringstream& put (char c) { iwrite (uint8_t(c)); return *this; }
int vformat (const char* fmt, va_list args);
int format (const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
inline uint16_t width (void) const { return _width; }
inline void width (uint16_t w) { _width = w; }
inline void set_width (uint16_t w) { _width = w; }
inline char fill (void) const { return _fill; }
inline void fill (char c) { _fill = c; }
inline uint8_t precision (void) const { return _precision; }
inline void precision (uint8_t v) { _precision = v; }
inline void set_precision (uint8_t v) { _precision = v; }
void link (void* p, size_type n) noexcept;
inline void link (memlink& l) { link (l.data(), l.writable_size()); }
inline const string& str (void) { flush(); return _buffer; }
void str (const string& s);
ostringstream& write (const void* buffer, size_type size);
inline ostringstream& write (const cmemlink& buf) { return write (buf.begin(), buf.size()); }
inline ostringstream& seekp (off_t p, seekdir d =beg) { ostream::seekp(p,d); return *this; }
virtual ostream& flush (void) override { ostream::flush(); _buffer.resize (pos()); return *this; }
virtual size_type overflow (size_type n = 1) override;
protected:
inline void reserve (size_type n) { _buffer.reserve (n, false); }
inline size_type capacity (void) const { return _buffer.capacity(); }
private:
inline void write_strz (const char*) { assert (!"Writing nul characters into a text stream is not allowed"); }
inline char* encode_dec (char* fmt, uint32_t n) const noexcept;
void fmtstring (char* fmt, const char* typestr, bool bInteger) const;
template <typename T>
void iformat (T v);
private:
string _buffer; ///< The output buffer.
fmtflags _flags; ///< See ios_base::fmtflags.
uint16_t _width; ///< Field width.
uint8_t _precision; ///< Number of digits after the decimal separator.
char _fill; ///< Character for padding variable width fields (space or 0 only)
};
//----------------------------------------------------------------------
template <typename T>
inline const char* printf_typestring (const T&) { return ""; }
#define PRINTF_TYPESTRING_SPEC(type,str) \
template <> inline const char* printf_typestring (const type&) { return str; }
PRINTF_TYPESTRING_SPEC (short, "hd")
PRINTF_TYPESTRING_SPEC (unsigned short, "hu")
PRINTF_TYPESTRING_SPEC (int, "d")
PRINTF_TYPESTRING_SPEC (unsigned int, "u")
PRINTF_TYPESTRING_SPEC (long, "ld")
PRINTF_TYPESTRING_SPEC (unsigned long, "lu")
/*PRINTF_TYPESTRING_SPEC (float, "f")
PRINTF_TYPESTRING_SPEC (double, "lf")
PRINTF_TYPESTRING_SPEC (long double, "Lf")*/
#if HAVE_LONG_LONG
PRINTF_TYPESTRING_SPEC (long long, "lld")
PRINTF_TYPESTRING_SPEC (unsigned long long, "llu")
#endif
#undef PRINTF_TYPESTRING_SPEC
template <typename T>
void ostringstream::iformat (T v)
{
char fmt [16];
fmtstring (fmt, printf_typestring(v), numeric_limits<T>::is_integer);
format (fmt, v);
}
void ostringstream::iwrite (fmtflags_bits f)
{
if (f & basefield) setf (f, basefield);
else if (f & floatfield) setf (f, floatfield);
else if (f & adjustfield) setf (f, adjustfield);
setf (f);
}
//----------------------------------------------------------------------
template <typename T> struct object_text_writer {
inline void operator()(ostringstream& os, const T& v) const { v.text_write (os); }
};
template <typename T> struct integral_text_object_writer {
inline void operator()(ostringstream& os, const T& v) const { os.iwrite (v); }
};
template <typename T>
inline ostringstream& operator<< (ostringstream& os, const T& v) {
typedef typename tm::Select <tm::TypeTraits<T>::isFundamental
|| tm::TypeTraits<T>::isPointer
|| tm::Conversion<T,long>::exists,
integral_text_object_writer<T>, object_text_writer<T> >::Result object_writer_t;
object_writer_t()(os, v);
return os;
}
// Needed because if called with a char[], numeric_limits will not work. Should be removed if I find out how to partial specialize for arrays...
inline ostringstream& operator<< (ostringstream& os, const char* v)
{ os.iwrite (v); return os; }
inline ostringstream& operator<< (ostringstream& os, char* v)
{ os.iwrite (v); return os; }
//----------------------------------------------------------------------
// Object writer operators
template <> struct object_text_writer<string> {
inline void operator()(ostringstream& os, const string& v) const { os.iwrite (v); }
};
template <typename T> struct integral_text_object_writer<T*> {
inline void operator() (ostringstream& os, const T* const& v) const
{ os.iwrite (uintptr_t(v)); }
};
//----------------------------------------------------------------------
// Manipulators
namespace {
static constexpr const struct Sendl {
inline constexpr Sendl (void) {}
inline void text_write (ostringstream& os) const { os << '\n'; os.flush(); }
inline void write (ostream& os) const { os.iwrite ('\n'); }
} endl;
static constexpr const struct Sflush {
inline constexpr Sflush (void) {}
inline void text_write (ostringstream& os) const { os.flush(); }
inline void write (ostringstream& os) const { os.flush(); }
inline void write (ostream&) const { }
} flush;
constexpr const char ends = '\0'; ///< End of string character.
} // namespace
struct setiosflags {
inline constexpr setiosflags (ios_base::fmtflags f) : _f(f) {}
inline void text_write (ostringstream& os) const { os.setf(_f); }
private:
const ios_base::fmtflags _f;
};
struct resetiosflags {
inline constexpr resetiosflags (ios_base::fmtflags f) : _f(f) {}
inline void text_write (ostringstream& os) const { os.unsetf(_f); }
private:
const ios_base::fmtflags _f;
};
class setw {
uint16_t _w;
public:
inline constexpr setw (uint16_t w) : _w(w) {}
inline void text_write (ostringstream& os) const { os.width(_w); }
inline void write (ostringstream& os) const { os.width(_w); }
};
class setfill {
char _c;
public:
inline constexpr setfill (char c) : _c(c) {}
inline void text_write (ostringstream& os) const { os.fill(_c); }
inline void write (ostringstream& os) const { os.fill(_c); }
};
class setprecision {
uint8_t _p;
public:
inline constexpr setprecision (uint8_t p) : _p(p) {}
inline void text_write (ostringstream& os) const { os.precision(_p); }
inline void write (ostringstream& os) const { os.precision(_p); }
};
} // namespace ustl

View File

@ -0,0 +1,92 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//
/// \file strmsize.h
/// \brief This file contains stream_size_of functions for basic types and *STREAMABLE macros.
/// stream_size_of functions return the size of the object's data that is written or
/// read from a stream.
#pragma once
namespace ustl {
/// For partial specialization of stream_size_of for objects
template <typename T> struct object_stream_size {
inline streamsize operator()(const T& v) const { return v.stream_size(); }
};
template <typename T> struct integral_object_stream_size {
inline streamsize operator()(const T& v) const { return sizeof(v); }
};
/// Returns the size of the given object. Overloads for standard types are available.
template <typename T>
inline streamsize stream_size_of (const T& v) {
typedef typename tm::Select <numeric_limits<T>::is_integral,
integral_object_stream_size<T>, object_stream_size<T> >::Result stream_sizer_t;
return stream_sizer_t()(v);
}
/// \brief Returns the recommended stream alignment for type \p T. Override with ALIGNOF.
/// Because this is occasionally called with a null value, do not access the argument!
template <typename T>
inline size_t stream_align_of (const T&)
{
if (numeric_limits<T>::is_integral)
return __alignof__(T);
return 4;
}
#define ALIGNOF(type,grain) \
namespace ustl { \
template <> inline size_t stream_align_of (const type&) { return grain; } }
} // namespace ustl
//
// Extra overloads in this macro are needed because it is the one used for
// marshalling pointers. Passing a pointer to stream_size_of creates a
// conversion ambiguity between converting to const pointer& and converting
// to bool; the compiler always chooses the bool conversion (because it
// requires 1 conversion instead of 2 for the other choice). There is little
// point in adding the overloads to other macros, since they are never used
// for pointers.
//
/// Declares that T is to be written as is into binary streams.
#define INTEGRAL_STREAMABLE(T) \
namespace ustl { \
inline istream& operator>> (istream& is, T& v) { is.iread(v); return is; } \
inline ostream& operator<< (ostream& os, const T& v) { os.iwrite(v); return os; } \
inline ostream& operator<< (ostream& os, T& v) { os.iwrite(v); return os; } \
template<> inline streamsize stream_size_of(const T& v) { return sizeof(v); } \
}
/// Declares that T contains read, write, and stream_size methods. This is no longer needed and is deprecated.
#define STD_STREAMABLE(T)
/// Declares \p T to be writable to text streams. This is no longer needed and is deprecated.
#define TEXT_STREAMABLE(T)
/// Declares that T is to be cast into TSUB for streaming.
#define CAST_STREAMABLE(T,TSUB) \
namespace ustl { \
inline istream& operator>> (istream& is, T& v) { TSUB sv; is >> sv; v = T(sv); return is; } \
inline ostream& operator<< (ostream& os, const T& v) { os << TSUB(v); return os; } \
template<> inline streamsize stream_size_of(const T& v) { return stream_size_of (TSUB(v)); } \
}
/// Placed into a class it declares the methods required by STD_STREAMABLE. Syntactic sugar.
#define DECLARE_STD_STREAMABLE \
public: \
void read (istream& is); \
void write (ostream& os) const; \
streamsize stream_size (void) const
/// Specifies that \p T is printed by using it as an index into \p Names string array.
#define LOOKUP_TEXT_STREAMABLE(T,Names,nNames) \
namespace ustl { \
inline ostringstream& operator<< (ostringstream& os, const T& v) { \
os << Names[min(uoff_t(v),uoff_t(nNames-1))]; \
return os; \
} \
}

View File

@ -0,0 +1,266 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2007 by Mike Sharov <msharov@users.sourceforge.net>
//
// This implementation is adapted from the Loki library, distributed under
// the MIT license with Copyright (c) 2001 by Andrei Alexandrescu.
#pragma once
#include "typelist.h"
namespace ustl {
namespace tm {
//----------------------------------------------------------------------
// Type classes and type modifiers
//----------------------------------------------------------------------
typedef tl::Seq<unsigned char, unsigned short, unsigned, unsigned long>::Type
StdUnsignedInts;
typedef tl::Seq<signed char, short, int, long>::Type StdSignedInts;
typedef tl::Seq<bool, char, wchar_t>::Type StdOtherInts;
typedef tl::Seq</*float, double*/>::Type StdFloats;
template <typename U> struct Identity { typedef U Result; };
template <typename U> struct AddPointer { typedef U* Result; };
template <typename U> struct AddPointer<U&> { typedef U* Result; };
template <typename U> struct AddReference { typedef U& Result; };
template <typename U> struct AddReference<U&> { typedef U& Result; };
template <> struct AddReference<void> { typedef NullType Result; };
template <typename U> struct AddParameterType { typedef const U& Result; };
template <typename U> struct AddParameterType<U&> { typedef U& Result; };
template <> struct AddParameterType<void> { typedef NullType Result; };
template <typename U> struct RemoveReference { typedef U Result; };
template <typename U> struct RemoveReference<U&> { typedef U Result; };
#if HAVE_CPP11
template <typename U> struct RemoveReference<U&&> { typedef U Result; };
#endif
template <bool, typename T> struct EnableIf { typedef void Result; };
template <typename T> struct EnableIf<true, T> { typedef T Result; };
//----------------------------------------------------------------------
// Function pointer testers
//----------------------------------------------------------------------
// Macros expand to numerous parameters
template <typename T>
struct IsFunctionPointerRaw { enum { result = false}; };
template <typename T>
struct IsMemberFunctionPointerRaw { enum { result = false}; };
#define TM_FPR_MAXN 9
#define TM_FPR_TYPE(n) PASTE(T,n)
#define TM_FPR_TYPENAME(n) typename TM_FPR_TYPE(n)
// First specialize for regular functions
template <typename T>
struct IsFunctionPointerRaw<T(*)(void)>
{enum {result = true};};
#define TM_FPR_SPEC(n) \
template <typename T, COMMA_LIST(n, TM_FPR_TYPENAME)> \
struct IsFunctionPointerRaw<T(*)(COMMA_LIST(n, TM_FPR_TYPE))> \
{ enum { result = true }; }
LIST (TM_FPR_MAXN, TM_FPR_SPEC, ;);
// Then for those with an ellipsis argument
template <typename T>
struct IsFunctionPointerRaw<T(*)(...)>
{enum {result = true};};
#define TM_FPR_SPEC_ELLIPSIS(n) \
template <typename T, COMMA_LIST(n, TM_FPR_TYPENAME)> \
struct IsFunctionPointerRaw<T(*)(COMMA_LIST(n, TM_FPR_TYPE), ...)> \
{ enum { result = true }; }
LIST (TM_FPR_MAXN, TM_FPR_SPEC_ELLIPSIS, ;);
// Then for member function pointers
template <typename T, typename S>
struct IsMemberFunctionPointerRaw<T (S::*)(void)>
{ enum { result = true }; };
#define TM_MFPR_SPEC(n) \
template <typename T, typename S, COMMA_LIST(n, TM_FPR_TYPENAME)> \
struct IsMemberFunctionPointerRaw<T (S::*)(COMMA_LIST(n, TM_FPR_TYPE))> \
{ enum { result = true };};
LIST (TM_FPR_MAXN, TM_MFPR_SPEC, ;);
// Then for member function pointers with an ellipsis argument
template <typename T, typename S>
struct IsMemberFunctionPointerRaw<T (S::*)(...)>
{ enum { result = true }; };
#define TM_MFPR_SPEC_ELLIPSIS(n) \
template <typename T, typename S, COMMA_LIST(n, TM_FPR_TYPENAME)> \
struct IsMemberFunctionPointerRaw<T (S::*)(COMMA_LIST(n, TM_FPR_TYPE), ...)> \
{ enum { result = true }; };
LIST (TM_FPR_MAXN, TM_MFPR_SPEC_ELLIPSIS, ;);
// Then for const member function pointers (getting tired yet?)
template <typename T, typename S>
struct IsMemberFunctionPointerRaw<T (S::*)(void) const>
{ enum { result = true }; };
#define TM_CMFPR_SPEC(n) \
template <typename T, typename S, COMMA_LIST(n, TM_FPR_TYPENAME)> \
struct IsMemberFunctionPointerRaw<T (S::*)(COMMA_LIST(n, TM_FPR_TYPE)) const> \
{ enum { result = true };};
LIST (TM_FPR_MAXN, TM_CMFPR_SPEC, ;);
// Finally for const member function pointers with an ellipsis argument (whew!)
template <typename T, typename S>
struct IsMemberFunctionPointerRaw<T (S::*)(...) const>
{ enum { result = true }; };
#define TM_CMFPR_SPEC_ELLIPSIS(n) \
template <typename T, typename S, COMMA_LIST(n, TM_FPR_TYPENAME)> \
struct IsMemberFunctionPointerRaw<T (S::*)(COMMA_LIST(n, TM_FPR_TYPE), ...) const> \
{ enum { result = true }; };
LIST (TM_FPR_MAXN, TM_CMFPR_SPEC_ELLIPSIS, ;);
#undef TM_FPR_SPEC
#undef TM_FPR_SPEC_ELLIPSIS
#undef TM_MFPR_SPEC
#undef TM_MFPR_SPEC_ELLIPSIS
#undef TM_CMFPR_SPEC
#undef TM_CMFPR_SPEC_ELLIPSIS
#undef TM_FPR_TYPENAME
#undef TM_FPR_TYPE
#undef TM_FPR_MAXN
//----------------------------------------------------------------------
// Type traits template
//----------------------------------------------------------------------
/// Figures out at compile time various properties of any given type
/// Invocations (T is a type, TypeTraits<T>::Propertie):
///
/// - isPointer : returns true if T is a pointer type
/// - PointeeType : returns the type to which T points if T is a pointer
/// type, NullType otherwise
/// - isReference : returns true if T is a reference type
/// - isLValue : returns true if T is an lvalue
/// - isRValue : returns true if T is an rvalue
/// - ReferredType : returns the type to which T refers if T is a reference
/// type, NullType otherwise
/// - isMemberPointer : returns true if T is a pointer to member type
/// - isStdUnsignedInt: returns true if T is a standard unsigned integral type
/// - isStdSignedInt : returns true if T is a standard signed integral type
/// - isStdIntegral : returns true if T is a standard integral type
/// - isStdFloat : returns true if T is a standard floating-point type
/// - isStdArith : returns true if T is a standard arithmetic type
/// - isStdFundamental: returns true if T is a standard fundamental type
/// - isUnsignedInt : returns true if T is a unsigned integral type
/// - isSignedInt : returns true if T is a signed integral type
/// - isIntegral : returns true if T is a integral type
/// - isFloat : returns true if T is a floating-point type
/// - isArith : returns true if T is a arithmetic type
/// - isFundamental : returns true if T is a fundamental type
/// - ParameterType : returns the optimal type to be used as a parameter for
/// functions that take Ts
/// - isConst : returns true if T is a const-qualified type
/// - NonConstType : Type with removed 'const' qualifier from T, if any
/// - isVolatile : returns true if T is a volatile-qualified type
/// - NonVolatileType : Type with removed 'volatile' qualifier from T, if any
/// - UnqualifiedType : Type with removed 'const' and 'volatile' qualifiers from
/// T, if any
/// - ConstParameterType: returns the optimal type to be used as a parameter
/// for functions that take 'const T's
///
template <typename T>
class TypeTraits {
private:
#define TMTT1 template <typename U> struct
#define TMTT2 template <typename U, typename V> struct
TMTT1 ReferenceTraits { enum { result = false, lvalue = true, rvalue = false }; typedef U ReferredType; };
TMTT1 ReferenceTraits<U&> { enum { result = true, lvalue = true, rvalue = false }; typedef U ReferredType; };
TMTT1 PointerTraits { enum { result = false }; typedef NullType PointeeType; };
TMTT1 PointerTraits<U*> { enum { result = true }; typedef U PointeeType; };
TMTT1 PointerTraits<U*&> { enum { result = true }; typedef U PointeeType; };
TMTT1 PToMTraits { enum { result = false }; };
TMTT2 PToMTraits<U V::*> { enum { result = true }; };
TMTT2 PToMTraits<U V::*&> { enum { result = true }; };
TMTT1 FunctionPointerTraits { enum { result = IsFunctionPointerRaw<U>::result }; };
TMTT1 PToMFunctionTraits { enum { result = IsMemberFunctionPointerRaw<U>::result }; };
TMTT1 UnConst { typedef U Result; enum { isConst = false }; };
TMTT1 UnConst<const U> { typedef U Result; enum { isConst = true }; };
TMTT1 UnConst<const U&> { typedef U& Result; enum { isConst = true }; };
TMTT1 UnVolatile { typedef U Result; enum { isVolatile = false }; };
TMTT1 UnVolatile<volatile U>{ typedef U Result; enum { isVolatile = true }; };
TMTT1 UnVolatile<volatile U&> {typedef U& Result;enum { isVolatile = true }; };
#if HAVE_CPP11
TMTT1 ReferenceTraits<U&&> { enum { result = true, lvalue = false, rvalue = true }; typedef U ReferredType; };
TMTT1 PointerTraits<U*&&> { enum { result = true }; typedef U PointeeType; };
TMTT2 PToMTraits<U V::*&&> { enum { result = true }; };
TMTT1 UnConst<const U&&> { typedef U&& Result; enum { isConst = true }; };
TMTT1 UnVolatile<volatile U&&> {typedef U&& Result;enum { isVolatile = true }; };
#endif
#undef TMTT2
#undef TMTT1
public:
typedef typename UnConst<T>::Result
NonConstType;
typedef typename UnVolatile<T>::Result
NonVolatileType;
typedef typename UnVolatile<typename UnConst<T>::Result>::Result
UnqualifiedType;
typedef typename PointerTraits<UnqualifiedType>::PointeeType
PointeeType;
typedef typename ReferenceTraits<T>::ReferredType
ReferredType;
enum { isConst = UnConst<T>::isConst };
enum { isVolatile = UnVolatile<T>::isVolatile };
enum { isReference = ReferenceTraits<UnqualifiedType>::result };
enum { isLValue = ReferenceTraits<UnqualifiedType>::lvalue };
enum { isRValue = ReferenceTraits<UnqualifiedType>::rvalue };
enum { isFunction = FunctionPointerTraits<typename AddPointer<T>::Result >::result };
enum { isFunctionPointer = FunctionPointerTraits<
typename ReferenceTraits<UnqualifiedType>::ReferredType >::result };
enum { isMemberFunctionPointer= PToMFunctionTraits<
typename ReferenceTraits<UnqualifiedType>::ReferredType >::result };
enum { isMemberPointer = PToMTraits<
typename ReferenceTraits<UnqualifiedType>::ReferredType >::result ||
isMemberFunctionPointer };
enum { isPointer = PointerTraits<
typename ReferenceTraits<UnqualifiedType>::ReferredType >::result ||
isFunctionPointer };
enum { isStdUnsignedInt = tl::IndexOf<StdUnsignedInts, UnqualifiedType>::value >= 0 ||
tl::IndexOf<StdUnsignedInts,
typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0};
enum { isStdSignedInt = tl::IndexOf<StdSignedInts, UnqualifiedType>::value >= 0 ||
tl::IndexOf<StdSignedInts,
typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0};
enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt ||
tl::IndexOf<StdOtherInts, UnqualifiedType>::value >= 0 ||
tl::IndexOf<StdOtherInts,
typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0};
enum { isStdFloat = tl::IndexOf<StdFloats, UnqualifiedType>::value >= 0 ||
tl::IndexOf<StdFloats,
typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0};
enum { isStdArith = isStdIntegral || isStdFloat };
enum { isStdFundamental = isStdArith || isStdFloat || Conversion<T, void>::sameType };
enum { isUnsignedInt = isStdUnsignedInt };
enum { isUnsigned = isUnsignedInt || isPointer };
enum { isSignedInt = isStdSignedInt };
enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt };
enum { isFloat = isStdFloat };
enum { isSigned = isSignedInt || isFloat };
enum { isArith = isIntegral || isFloat };
enum { isFundamental = isStdFundamental || isArith };
typedef typename Select<isStdArith || isPointer || isMemberPointer, T,
typename AddParameterType<T>::Result>::Result
ParameterType;
};
} // namespace tm
} // namespace ustl

View File

@ -0,0 +1,219 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2007 by Mike Sharov <msharov@users.sourceforge.net>
//
// This implementation is adapted from the Loki library, distributed under
// the MIT license with Copyright (c) 2001 by Andrei Alexandrescu.
#pragma once
#include "metamac.h"
#include "typet.h"
namespace ustl {
namespace tm {
/// The building block of typelists. Use it throught the Seq templates.
template <typename T, typename U>
struct Typelist {
typedef T Head;
typedef U Tail;
};
/// Namespace containing typelist-related functionality.
namespace tl {
//----------------------------------------------------------------------
// Seq template definitions. The macros expand to a spec per arg count
//
#define TL_MAX_SEQ_TYPES 9
#define TL_MAX_SEQ_SPECS 8
#define TL_SEQ_TYPE(n) T##n
#define TL_SEQ_TYPENAME(n) typename TL_SEQ_TYPE(n)
#define TL_SEQ_NULLTYPE_DEFAULT(n) TL_SEQ_TYPENAME(n)=NullType
#define TL_SEQ_TL_END(n) >
#define TL_SEQ_ONE_TYPELIST(n) Typelist<TL_SEQ_TYPE(n)
/// Creates a typelist from a sequence of types
template <COMMA_LIST(TL_MAX_SEQ_TYPES,TL_SEQ_NULLTYPE_DEFAULT)>
struct Seq {
typedef COMMA_LIST(TL_MAX_SEQ_TYPES,TL_SEQ_ONE_TYPELIST),
NullType REPEAT(TL_MAX_SEQ_TYPES,TL_SEQ_TL_END) Type;
};
#define TL_SEQ_SPEC(n) \
template <COMMA_LIST (n, TL_SEQ_TYPENAME)> \
struct Seq<COMMA_LIST (n, TL_SEQ_TYPE)> { \
typedef COMMA_LIST(n,TL_SEQ_ONE_TYPELIST), \
NullType REPEAT(n,TL_SEQ_TL_END) Type; \
}
LIST(TL_MAX_SEQ_SPECS,TL_SEQ_SPEC, ;);
#undef TL_SEQ_SPEC
#undef TL_SEQ_TL_END
#undef TL_SEQ_ONE_TYPELIST
#undef TL_SEQ_NULLTYPE_DEFAULT
#undef TL_SEQ_TYPE
#undef TL_MAX_SEQ_SPECS
//----------------------------------------------------------------------
// Various utility functions follow.
/// Length<List>::value is the number of types in the typelist.
template <typename List> struct Length { };
template <> struct Length<NullType> { enum { value = 0 }; };
template <typename T, typename U>
struct Length<Typelist<T, U> > { enum { value = 1 + Length<U>::value }; };
/// TypeAt<List, i>::Result is the ith type in List
template <typename List, unsigned index> struct TypeAt { };
template <class Head, class Tail>
struct TypeAt<Typelist<Head, Tail>, 0> {
typedef Head Result;
};
template <class Head, class Tail, unsigned index>
struct TypeAt<Typelist<Head, Tail>, index> {
typedef typename TypeAt<Tail, index-1>::Result Result;
};
/// TypeAtNonStrict<List,i,DefaultType>::Result is List[i] or DefaultType if out of range.
template <typename List, unsigned index, typename DefaultType = NullType>
struct TypeAtNonStrict {
typedef DefaultType Result;
};
template <typename Head, typename Tail, typename DefaultType>
struct TypeAtNonStrict<Typelist<Head, Tail>, 0, DefaultType> {
typedef Head Result;
};
template <typename Head, typename Tail, unsigned index, typename DefaultType>
struct TypeAtNonStrict<Typelist<Head, Tail>, index, DefaultType> {
typedef typename TypeAtNonStrict<Tail, index-1, DefaultType>::Result Result;
};
/// IndexOf<List,T>::value is the position of T in List, or -1 if not found.
template <typename List, typename T> struct IndexOf;
template <typename T>
struct IndexOf<NullType, T> { enum { value = -1 }; };
template <typename T, typename Tail>
struct IndexOf<Typelist<T, Tail>, T> { enum { value = 0 }; };
template <typename Head, typename Tail, typename T>
struct IndexOf<Typelist<Head, Tail>, T> {
private:
enum { iintail = IndexOf<Tail, T>::value };
public:
enum { value = (iintail == -1 ? -1 : 1+iintail) };
};
/// Appends a type or a typelist to another in Append<TList, T>::Result
template <typename List, typename T> struct Append;
template <> struct Append<NullType, NullType> { typedef NullType Result; };
template <typename T> struct Append<NullType, T> {
typedef Typelist<T,NullType> Result;
};
template <typename Head, typename Tail>
struct Append<NullType, Typelist<Head, Tail> > {
typedef Typelist<Head, Tail> Result;
};
template <typename Head, typename Tail, typename T>
struct Append<Typelist<Head, Tail>, T> {
typedef Typelist<Head, typename Append<Tail, T>::Result> Result;
};
// Erase<List, T>::Result contains List without the first T.
template <typename TList, typename T> struct Erase;
template <typename T>
struct Erase<NullType, T> { typedef NullType Result; };
template <typename T, typename Tail>
struct Erase<Typelist<T, Tail>, T> { typedef Tail Result; };
template <typename Head, typename Tail, typename T>
struct Erase<Typelist<Head, Tail>, T> {
typedef Typelist<Head, typename Erase<Tail, T>::Result> Result;
};
// EraseAll<List, T>::Result contains List without any T.
template <typename List, typename T> struct EraseAll;
template <typename T>
struct EraseAll<NullType, T> { typedef NullType Result; };
template <typename T, typename Tail>
struct EraseAll<Typelist<T, Tail>, T> {
typedef typename EraseAll<Tail, T>::Result Result;
};
template <typename Head, typename Tail, typename T>
struct EraseAll<Typelist<Head, Tail>, T> {
typedef Typelist<Head, typename EraseAll<Tail, T>::Result> Result;
};
/// Removes all duplicate types in a typelist
template <typename List> struct NoDuplicates;
template <> struct NoDuplicates<NullType> { typedef NullType Result; };
template <typename Head, typename Tail>
struct NoDuplicates< Typelist<Head, Tail> > {
private:
typedef typename NoDuplicates<Tail>::Result L1;
typedef typename Erase<L1, Head>::Result L2;
public:
typedef Typelist<Head, L2> Result;
};
// Replaces the first occurence of a type in a typelist, with another type
template <typename List, typename T, typename U> struct Replace;
template <typename T, typename U>
struct Replace<NullType, T, U> { typedef NullType Result; };
template <typename T, typename Tail, typename U>
struct Replace<Typelist<T, Tail>, T, U> {
typedef Typelist<U, Tail> Result;
};
template <typename Head, typename Tail, typename T, typename U>
struct Replace<Typelist<Head, Tail>, T, U> {
typedef Typelist<Head, typename Replace<Tail, T, U>::Result> Result;
};
// Replaces all occurences of a type in a typelist, with another type
template <typename List, typename T, typename U> struct ReplaceAll;
template <typename T, typename U>
struct ReplaceAll<NullType, T, U> { typedef NullType Result; };
template <typename T, typename Tail, typename U>
struct ReplaceAll<Typelist<T, Tail>, T, U> {
typedef Typelist<U, typename ReplaceAll<Tail, T, U>::Result> Result;
};
template <typename Head, typename Tail, typename T, typename U>
struct ReplaceAll<Typelist<Head, Tail>, T, U> {
typedef Typelist<Head, typename ReplaceAll<Tail, T, U>::Result> Result;
};
// Reverses a typelist
template <typename List> struct Reverse;
template <> struct Reverse<NullType> { typedef NullType Result; };
template <typename Head, typename Tail>
struct Reverse< Typelist<Head, Tail> > {
typedef typename Append<typename Reverse<Tail>::Result, Head>::Result Result;
};
// Finds the type in a typelist that is the most derived from a given type
template <typename List, typename T> struct MostDerived;
template <typename T> struct MostDerived<NullType, T> { typedef T Result; };
template <typename Head, typename Tail, typename T>
struct MostDerived<Typelist<Head, Tail>, T> {
private:
typedef typename MostDerived<Tail, T>::Result Candidate;
public:
typedef typename Select<SuperSubclass<Candidate,Head>::value, Head, Candidate>::Result Result;
};
// Arranges the types in a typelist so that the most derived types appear first
template <typename List> struct DerivedToFront;
template <> struct DerivedToFront<NullType> { typedef NullType Result; };
template <typename Head, typename Tail>
struct DerivedToFront< Typelist<Head, Tail> > {
private:
typedef typename MostDerived<Tail, Head>::Result TheMostDerived;
typedef typename Replace<Tail, TheMostDerived, Head>::Result Temp;
typedef typename DerivedToFront<Temp>::Result L;
public:
typedef Typelist<TheMostDerived, L> Result;
};
//----------------------------------------------------------------------
} // namespace tl
} // namespace tm
} // namespace ustl

View File

@ -0,0 +1,96 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2007 by Mike Sharov <msharov@users.sourceforge.net>
//
// This implementation is adapted from the Loki library, distributed under
// the MIT license with Copyright (c) 2001 by Andrei Alexandrescu.
#pragma once
namespace ustl {
/// Template metaprogramming tools
namespace tm {
/// An empty type useful as a placeholder.
class NullType { };
/// Converts an integer to a type.
template <int v> struct Int2Type { enum { value = v }; };
/// Converts an type to a unique empty type.
template <typename T> struct Type2Type { typedef T OriginalType; };
/// Selects type Result = flag ? T : U
template <bool flag, typename T, typename U>
struct Select { typedef T Result; };
template <typename T, typename U>
struct Select<false, T, U> { typedef U Result; };
/// IsSameType<T,U>::value is true when T=U
template <typename T, typename U>
struct IsSameType { enum { value = false }; };
template <typename T>
struct IsSameType<T,T> { enum { value = true }; };
/// \brief Checks for conversion possibilities between T and U
/// Conversion<T,U>::exists is true if T is convertible to U
/// Conversion<T,U>::sameType is true if U is T
template <typename T, typename U>
struct Conversion {
private:
typedef char UT;
typedef short TT;
static UT Test (U);
static TT Test (...);
static T MakeT (void);
public:
enum {
exists = sizeof(UT) == sizeof(Test(MakeT())),
sameType = false
};
};
template <typename T>
struct Conversion<T, T> { enum { exists = true, sameType = true }; };
template <typename T>
struct Conversion<void, T> { enum { exists = false, sameType = false }; };
template <typename T>
struct Conversion<T, void> { enum { exists = false, sameType = false }; };
template <>
struct Conversion<void, void> { enum { exists = true, sameType = true }; };
/// SuperSubclass<T,U>::value is true when U is derived from T, or when U is T
template <typename T, typename U>
struct SuperSubclass {
enum { value = (::ustl::tm::Conversion<const volatile U*, const volatile T*>::exists &&
!::ustl::tm::Conversion<const volatile T*, const volatile void*>::sameType) };
enum { dontUseWithIncompleteTypes = sizeof(T)==sizeof(U) }; // Dummy enum to make sure that both classes are fully defined.
};
template <>
struct SuperSubclass<void, void> { enum { value = false }; };
template <typename U>
struct SuperSubclass<void, U> {
enum { value = false };
enum { dontUseWithIncompleteTypes = 0==sizeof(U) };
};
template <typename T>
struct SuperSubclass<T, void> {
enum { value = false };
enum { dontUseWithIncompleteTypes = 0==sizeof(T) };
};
/// SuperSubclassStrict<T,U>::value is true when U is derived from T
template <typename T, typename U>
struct SuperSubclassStrict {
enum { value = SuperSubclass<T,U>::value &&
!::ustl::tm::Conversion<const volatile T*, const volatile U*>::sameType };
};
#if !HAVE_CPP11
// static assert support
template <bool> struct CompileTimeError;
template <> struct CompileTimeError<true> {};
#define static_assert(cond,msg) { ::ustl::tm::CompileTimeError<!!(cond)> ERROR_##msg; (void) ERROR_##msg; }
#endif
} // namespace tm
} // namespace ustl

View File

@ -0,0 +1,733 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "upair.h"
#include "ufunction.h"
#include "umemory.h"
#include "util/qsort.h"
namespace ustl {
/// Swaps corresponding elements of [first, last) and [result,)
/// \ingroup SwapAlgorithms
///
template <typename ForwardIterator1, typename ForwardIterator2>
inline ForwardIterator2 swap_ranges (ForwardIterator1 first, ForwardIterator2 last, ForwardIterator2 result)
{
for (; first != last; ++first, ++result)
iter_swap (first, result);
return result;
}
/// Returns the first iterator i in the range [first, last) such that
/// *i == value. Returns last if no such iterator exists.
/// \ingroup SearchingAlgorithms
///
template <typename InputIterator, typename EqualityComparable>
inline InputIterator find (InputIterator first, InputIterator last, const EqualityComparable& value)
{
while (first != last && !(*first == value))
++ first;
return first;
}
/// Returns the first iterator such that *i == *(i + 1)
/// \ingroup SearchingAlgorithms
///
template <typename ForwardIterator>
ForwardIterator adjacent_find (ForwardIterator first, ForwardIterator last)
{
if (first != last)
for (ForwardIterator prev = first; ++first != last; ++ prev)
if (*prev == *first)
return prev;
return last;
}
/// Returns the pointer to the first pair of unequal elements.
/// \ingroup SearchingAlgorithms
///
template <typename InputIterator>
pair<InputIterator,InputIterator>
mismatch (InputIterator first1, InputIterator last1, InputIterator first2)
{
while (first1 != last1 && *first1 == *first2)
++ first1, ++ first2;
return make_pair (first1, first2);
}
/// \brief Returns true if two ranges are equal.
/// This is an extension, present in uSTL and SGI STL.
/// \ingroup SearchingAlgorithms
///
template <typename InputIterator>
inline bool equal (InputIterator first1, InputIterator last1, InputIterator first2)
{
return mismatch (first1, last1, first2).first == last1;
}
/// Count finds the number of elements in [first, last) that are equal
/// to value. More precisely, the first version of count returns the
/// number of iterators i in [first, last) such that *i == value.
/// \ingroup SearchingAlgorithms
///
template <typename InputIterator, typename EqualityComparable>
inline size_t count (InputIterator first, InputIterator last, const EqualityComparable& value)
{
size_t total = 0;
for (; first != last; ++first)
if (*first == value)
++ total;
return total;
}
///
/// The first version of transform performs the operation op(*i) for each
/// iterator i in the range [first, last), and assigns the result of that
/// operation to *o, where o is the corresponding output iterator. That is,
/// for each n such that 0 <= n < last - first, it performs the assignment
/// *(result + n) = op(*(first + n)).
/// The return value is result + (last - first).
/// \ingroup MutatingAlgorithms
/// \ingroup PredicateAlgorithms
///
template <typename InputIterator, typename OutputIterator, typename UnaryFunction>
inline OutputIterator transform (InputIterator first, InputIterator last, OutputIterator result, UnaryFunction op)
{
for (; first != last; ++result, ++first)
*result = op (*first);
return result;
}
///
/// The second version of transform is very similar, except that it uses a
/// Binary Function instead of a Unary Function: it performs the operation
/// op(*i1, *i2) for each iterator i1 in the range [first1, last1) and assigns
/// the result to *o, where i2 is the corresponding iterator in the second
/// input range and where o is the corresponding output iterator. That is,
/// for each n such that 0 <= n < last1 - first1, it performs the assignment
/// *(result + n) = op(*(first1 + n), *(first2 + n).
/// The return value is result + (last1 - first1).
/// \ingroup MutatingAlgorithms
/// \ingroup PredicateAlgorithms
///
template <typename InputIterator1, typename InputIterator2, typename OutputIterator, typename BinaryFunction>
inline OutputIterator transform (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryFunction op)
{
for (; first1 != last1; ++result, ++first1, ++first2)
*result = op (*first1, *first2);
return result;
}
/// Replace replaces every element in the range [first, last) equal to
/// old_value with new_value. That is: for every iterator i,
/// if *i == old_value then it performs the assignment *i = new_value.
/// \ingroup MutatingAlgorithms
///
template <typename ForwardIterator, typename T>
inline void replace (ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value)
{
for (; first != last; ++first)
if (*first == old_value)
*first = new_value;
}
/// Replace_copy copies elements from the range [first, last) to the range
/// [result, result + (last-first)), except that any element equal to old_value
/// is not copied; new_value is copied instead. More precisely, for every
/// integer n such that 0 <= n < last-first, replace_copy performs the
/// assignment *(result+n) = new_value if *(first+n) == old_value, and
/// *(result+n) = *(first+n) otherwise.
/// \ingroup MutatingAlgorithms
///
template <typename InputIterator, typename OutputIterator, typename T>
inline OutputIterator replace_copy (InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value)
{
for (; first != last; ++result, ++first)
*result = (*first == old_value) ? new_value : *first;
}
/// Generate assigns the result of invoking gen, a function object that
/// takes no arguments, to each element in the range [first, last).
/// \ingroup GeneratorAlgorithms
/// \ingroup PredicateAlgorithms
///
template <typename ForwardIterator, typename Generator>
inline void generate (ForwardIterator first, ForwardIterator last, Generator gen)
{
for (; first != last; ++first)
*first = gen();
}
/// Generate_n assigns the result of invoking gen, a function object that
/// takes no arguments, to each element in the range [first, first+n).
/// The return value is first + n.
/// \ingroup GeneratorAlgorithms
/// \ingroup PredicateAlgorithms
///
template <typename OutputIterator, typename Generator>
inline OutputIterator generate_n (OutputIterator first, size_t n, Generator gen)
{
for (uoff_t i = 0; i != n; ++i, ++first)
*first = gen();
return first;
}
/// \brief Reverse reverses a range.
/// That is: for every i such that 0 <= i <= (last - first) / 2),
/// it exchanges *(first + i) and *(last - (i + 1)).
/// \ingroup MutatingAlgorithms
///
template <typename BidirectionalIterator>
inline void reverse (BidirectionalIterator first, BidirectionalIterator last)
{
for (; distance (first, --last) > 0; ++first)
iter_swap (first, last);
}
/// \brief Reverses [first,last) and writes it to \p output.
/// \ingroup MutatingAlgorithms
///
template <typename BidirectionalIterator, typename OutputIterator>
inline OutputIterator reverse_copy (BidirectionalIterator first, BidirectionalIterator last, OutputIterator result)
{
for (; first != last; ++result)
*result = *--last;
return result;
}
/// \brief Exchanges ranges [first, middle) and [middle, last)
/// \ingroup MutatingAlgorithms
///
template <typename ForwardIterator>
ForwardIterator rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last)
{
if (first == middle || middle == last)
return first;
reverse (first, middle);
reverse (middle, last);
for (;first != middle && middle != last; ++first)
iter_swap (first, --last);
reverse (first, (first == middle ? last : middle));
return first;
}
/// Specialization for pointers, which can be treated identically.
template <typename T>
inline T* rotate (T* first, T* middle, T* last)
{
rotate_fast (first, middle, last);
return first;
}
/// \brief Exchanges ranges [first, middle) and [middle, last) into \p result.
/// \ingroup MutatingAlgorithms
///
template <typename ForwardIterator, typename OutputIterator>
inline OutputIterator rotate_copy (ForwardIterator first, ForwardIterator middle, ForwardIterator last, OutputIterator result)
{
return copy (first, middle, copy (middle, last, result));
}
/// \brief Combines two sorted ranges.
/// \ingroup SortingAlgorithms
///
template <typename InputIterator1, typename InputIterator2, typename OutputIterator>
OutputIterator merge (InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2, OutputIterator result)
{
for (; first1 != last1 && first2 != last2; ++result) {
if (*first1 < *first2)
*result = *first1++;
else
*result = *first2++;
}
if (first1 < last1)
return copy (first1, last1, result);
else
return copy (first2, last2, result);
}
/// Combines two sorted ranges from the same container.
/// \ingroup SortingAlgorithms
///
template <typename InputIterator>
void inplace_merge (InputIterator first, InputIterator middle, InputIterator last)
{
for (; middle != last; ++first) {
while (*first < *middle)
++ first;
reverse (first, middle);
reverse (first, ++middle);
}
}
/// Remove_copy copies elements that are not equal to value from the range
/// [first, last) to a range beginning at result. The return value is the
/// end of the resulting range. This operation is stable, meaning that the
/// relative order of the elements that are copied is the same as in the
/// range [first, last).
/// \ingroup MutatingAlgorithms
///
template <typename InputIterator, typename OutputIterator, typename T>
OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, const T& value)
{
for (; first != last; ++first) {
if (!(*first == value)) {
*result = *first;
++ result;
}
}
return result;
}
/// Remove_copy copies elements pointed to by iterators in [rfirst, rlast)
/// from the range [first, last) to a range beginning at result. The return
/// value is the end of the resulting range. This operation is stable, meaning
/// that the relative order of the elements that are copied is the same as in the
/// range [first, last). Range [rfirst, rlast) is assumed to be sorted.
/// This algorithm is a uSTL extension.
/// \ingroup MutatingAlgorithms
///
template <typename InputIterator, typename OutputIterator, typename RInputIterator>
OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, RInputIterator rfirst, RInputIterator rlast)
{
for (; first != last; ++first) {
while (rfirst != rlast && *rfirst < first)
++ rfirst;
if (rfirst == rlast || first != *rfirst) {
*result = *first;
++ result;
}
}
return result;
}
/// Remove removes from the range [first, last) all elements that are equal to
/// value. That is, remove returns an iterator new_last such that the range
/// [first, new_last) contains no elements equal to value. [1] The iterators
/// in the range [new_last, last) are all still dereferenceable, but the
/// elements that they point to are unspecified. Remove is stable, meaning
/// that the relative order of elements that are not equal to value is
/// unchanged.
/// \ingroup MutatingAlgorithms
///
template <typename ForwardIterator, typename T>
inline ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& value)
{
return remove_copy (first, last, first, value);
}
/// Unique_copy copies elements from the range [first, last) to a range
/// beginning with result, except that in a consecutive group of duplicate
/// elements only the first one is copied. The return value is the end of
/// the range to which the elements are copied. This behavior is similar
/// to the Unix filter uniq.
/// \ingroup MutatingAlgorithms
///
template <typename InputIterator, typename OutputIterator>
OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result)
{
if (first != last) {
*result = *first;
while (++first != last)
if (!(*first == *result))
*++result = *first;
++ result;
}
return result;
}
/// Every time a consecutive group of duplicate elements appears in the range
/// [first, last), the algorithm unique removes all but the first element.
/// That is, unique returns an iterator new_last such that the range [first,
/// new_last) contains no two consecutive elements that are duplicates.
/// The iterators in the range [new_last, last) are all still dereferenceable,
/// but the elements that they point to are unspecified. Unique is stable,
/// meaning that the relative order of elements that are not removed is
/// unchanged.
/// \ingroup MutatingAlgorithms
///
template <typename ForwardIterator>
inline ForwardIterator unique (ForwardIterator first, ForwardIterator last)
{
return unique_copy (first, last, first);
}
/// Returns the furthermost iterator i in [first, last) such that,
/// for every iterator j in [first, i), *j < value
/// Assumes the range is sorted.
/// \ingroup SearchingAlgorithms
///
template <typename ForwardIterator, typename LessThanComparable>
ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const LessThanComparable& value)
{
ForwardIterator mid;
while (first != last) {
mid = advance (first, size_t(distance (first,last)) / 2);
if (*mid < value)
first = mid + 1;
else
last = mid;
}
return first;
}
/// Performs a binary search inside the sorted range.
/// \ingroup SearchingAlgorithms
///
template <typename ForwardIterator, typename LessThanComparable>
inline bool binary_search (ForwardIterator first, ForwardIterator last, const LessThanComparable& value)
{
ForwardIterator found = lower_bound (first, last, value);
return found != last && !(value < *found);
}
/// Returns the furthermost iterator i in [first,last) such that for
/// every iterator j in [first,i), value < *j is false.
/// \ingroup SearchingAlgorithms
///
template <typename ForwardIterator, typename LessThanComparable>
ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const LessThanComparable& value)
{
ForwardIterator mid;
while (first != last) {
mid = advance (first, size_t(distance (first,last)) / 2);
if (value < *mid)
last = mid;
else
first = mid + 1;
}
return last;
}
/// Returns pair<lower_bound,upper_bound>
/// \ingroup SearchingAlgorithms
///
template <typename ForwardIterator, typename LessThanComparable>
inline pair<ForwardIterator,ForwardIterator> equal_range (ForwardIterator first, ForwardIterator last, const LessThanComparable& value)
{
pair<ForwardIterator,ForwardIterator> rv;
rv.second = rv.first = lower_bound (first, last, value);
while (rv.second != last && !(value < *(rv.second)))
++ rv.second;
return rv;
}
/// Randomly permute the elements of the container.
/// \ingroup GeneratorAlgorithms
///
/*template <typename RandomAccessIterator>
void random_shuffle (RandomAccessIterator first, RandomAccessIterator last)
{
for (; first != last; ++ first)
iter_swap (first, first + (rand() % distance (first, last)));
}*/
/// \brief Generic compare function adaptor to pass to qsort
/// \ingroup FunctorObjects
template <typename ConstPointer, typename Compare>
int qsort_adapter (const void* p1, const void* p2)
{
ConstPointer i1 = reinterpret_cast<ConstPointer>(p1);
ConstPointer i2 = reinterpret_cast<ConstPointer>(p2);
Compare comp;
return comp (*i1, *i2) ? -1 : (comp (*i2, *i1) ? 1 : 0);
}
/// Sorts the container
/// \ingroup SortingAlgorithms
/// \ingroup PredicateAlgorithms
///
template <typename RandomAccessIterator, typename Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
typedef typename iterator_traits<RandomAccessIterator>::const_pointer const_pointer;
qsort (first, distance (first, last), sizeof(value_type),
&qsort_adapter<const_pointer, Compare>);
}
/// Sorts the container
/// \ingroup SortingAlgorithms
///
template <typename RandomAccessIterator>
inline void sort (RandomAccessIterator first, RandomAccessIterator last)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
sort (first, last, less<value_type>());
}
/// Sorts the container preserving order of equal elements.
/// \ingroup SortingAlgorithms
/// \ingroup PredicateAlgorithms
///
template <typename RandomAccessIterator, typename Compare>
void stable_sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
{
for (RandomAccessIterator j, i = first; ++i < last;) { // Insertion sort
for (j = i; j-- > first && comp(*i, *j);) ;
if (++j != i) rotate (j, i, i + 1);
}
}
/// Sorts the container
/// \ingroup SortingAlgorithms
///
template <typename RandomAccessIterator>
inline void stable_sort (RandomAccessIterator first, RandomAccessIterator last)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
stable_sort (first, last, less<value_type>());
}
/// \brief Searches for the first subsequence [first2,last2) in [first1,last1)
/// \ingroup SearchingAlgorithms
template <typename ForwardIterator1, typename ForwardIterator2>
inline ForwardIterator1 search (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2)
{
typedef typename iterator_traits<ForwardIterator1>::value_type value_type;
return search (first1, last1, first2, last2, equal_to<value_type>());
}
/// \brief Searches for the last subsequence [first2,last2) in [first1,last1)
/// \ingroup SearchingAlgorithms
template <typename ForwardIterator1, typename ForwardIterator2>
inline ForwardIterator1 find_end (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2)
{
typedef typename iterator_traits<ForwardIterator1>::value_type value_type;
return find_end (first1, last1, first2, last2, equal_to<value_type>());
}
/// \brief Searches for the first occurence of \p count \p values in [first, last)
/// \ingroup SearchingAlgorithms
template <typename Iterator, typename T>
inline Iterator search_n (Iterator first, Iterator last, size_t count, const T& value)
{
typedef typename iterator_traits<Iterator>::value_type value_type;
return search_n (first, last, count, value, equal_to<value_type>());
}
/// \brief Searches [first1,last1) for the first occurrence of an element from [first2,last2)
/// \ingroup SearchingAlgorithms
template <typename InputIterator, typename ForwardIterator>
inline InputIterator find_first_of (InputIterator first1, InputIterator last1, ForwardIterator first2, ForwardIterator last2)
{
typedef typename iterator_traits<InputIterator>::value_type value_type;
return find_first_of (first1, last1, first2, last2, equal_to<value_type>());
}
/// \brief Returns true if [first2,last2) is a subset of [first1,last1)
/// \ingroup ConditionAlgorithms
/// \ingroup SetAlgorithms
template <typename InputIterator1, typename InputIterator2>
inline bool includes (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2)
{
typedef typename iterator_traits<InputIterator1>::value_type value_type;
return includes (first1, last1, first2, last2, less<value_type>());
}
/// \brief Merges [first1,last1) with [first2,last2)
///
/// Result will contain every element that is in either set. If duplicate
/// elements are present, max(n,m) is placed in the result.
///
/// \ingroup SetAlgorithms
template <typename InputIterator1, typename InputIterator2, typename OutputIterator>
inline OutputIterator set_union (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result)
{
typedef typename iterator_traits<InputIterator1>::value_type value_type;
return set_union (first1, last1, first2, last2, result, less<value_type>());
}
/// \brief Creates a set containing elements shared by the given ranges.
/// \ingroup SetAlgorithms
template <typename InputIterator1, typename InputIterator2, typename OutputIterator>
inline OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result)
{
typedef typename iterator_traits<InputIterator1>::value_type value_type;
return set_intersection (first1, last1, first2, last2, result, less<value_type>());
}
/// \brief Removes from [first1,last1) elements present in [first2,last2)
/// \ingroup SetAlgorithms
template <typename InputIterator1, typename InputIterator2, typename OutputIterator>
inline OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result)
{
typedef typename iterator_traits<InputIterator1>::value_type value_type;
return set_difference (first1, last1, first2, last2, result, less<value_type>());
}
/// \brief Performs union of sets A-B and B-A.
/// \ingroup SetAlgorithms
template <typename InputIterator1, typename InputIterator2, typename OutputIterator>
inline OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result)
{
typedef typename iterator_traits<InputIterator1>::value_type value_type;
return set_symmetric_difference (first1, last1, first2, last2, result, less<value_type>());
}
/// \brief Returns true if the given range is sorted.
/// \ingroup ConditionAlgorithms
template <typename ForwardIterator>
inline bool is_sorted (ForwardIterator first, ForwardIterator last)
{
typedef typename iterator_traits<ForwardIterator>::value_type value_type;
return is_sorted (first, last, less<value_type>());
}
/// \brief Compares two given containers like strcmp compares strings.
/// \ingroup ConditionAlgorithms
template <typename InputIterator1, typename InputIterator2>
inline bool lexicographical_compare (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2)
{
typedef typename iterator_traits<InputIterator1>::value_type value_type;
return lexicographical_compare (first1, last1, first2, last2, less<value_type>());
}
/// \brief Creates the next lexicographical permutation of [first,last).
/// Returns false if no further permutations can be created.
/// \ingroup GeneratorAlgorithms
template <typename BidirectionalIterator>
inline bool next_permutation (BidirectionalIterator first, BidirectionalIterator last)
{
typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
return next_permutation (first, last, less<value_type>());
}
/// \brief Creates the previous lexicographical permutation of [first,last).
/// Returns false if no further permutations can be created.
/// \ingroup GeneratorAlgorithms
template <typename BidirectionalIterator>
inline bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last)
{
typedef typename iterator_traits<BidirectionalIterator>::value_type value_type;
return prev_permutation (first, last, less<value_type>());
}
/// Returns \p v clamped to the given range
template <typename T, typename Compare>
inline T clamp (const T& v, const T& l, const T& h, Compare comp)
{ return comp(v, l) ? l : comp(h, v) ? h : v; }
template <typename T>
inline T clamp (const T& v, const T& l, const T& h)
{ return v < l ? l : (h < v ? h : v); }
/// Returns iterator to the max element in [first,last)
/// \ingroup SearchingAlgorithms
template <typename ForwardIterator>
inline ForwardIterator max_element (ForwardIterator first, ForwardIterator last)
{
typedef typename iterator_traits<ForwardIterator>::value_type value_type;
return max_element (first, last, less<value_type>());
}
/// Returns iterator to the min element in [first,last)
/// \ingroup SearchingAlgorithms
template <typename ForwardIterator>
inline ForwardIterator min_element (ForwardIterator first, ForwardIterator last)
{
typedef typename iterator_traits<ForwardIterator>::value_type value_type;
return min_element (first, last, less<value_type>());
}
#if HAVE_CPP14
/// Returns min,max pair of the argument
template <typename T>
inline constexpr auto minmax (const T& a, const T& b)
{ return a < b ? make_pair<const T&,const T&>(a,b) : make_pair<const T&,const T&>(b,a); }
template <typename T>
inline constexpr auto minmax (T& a, T& b)
{ return a < b ? make_pair<T&,T&>(a,b) : make_pair<T&,T&>(b,a); }
template <typename T, typename Compare>
inline constexpr auto minmax (const T& a, const T& b, Compare comp)
{ return comp(a,b) ? make_pair<const T&,const T&>(a,b) : make_pair<const T&,const T&>(b,a); }
template <typename T> constexpr void minmax (T&& a, T&& b) = delete;
template <typename T, typename Compare> constexpr void minmax (const T& a, const T& b, Compare comp) = delete;
template <typename T>
auto minmax (std::initializer_list<T> l)
{
auto r = make_pair (*l.begin(),*l.begin());
for (auto& i : l) {
r.first = min (r.first, i);
r.second = max (r.second, i);
}
return r;
}
template <typename T, typename Compare>
auto minmax (std::initializer_list<T> l, Compare comp)
{
auto r = make_pair (*l.begin(),*l.begin());
for (auto& i : l) {
if (comp(i, r.first))
r.first = i;
if (comp(r.second, i))
r.second = i;
}
return r;
}
#endif
template <typename ForwardIterator>
pair<ForwardIterator,ForwardIterator> minmax_element (ForwardIterator first, ForwardIterator last)
{
pair<ForwardIterator,ForwardIterator> r = make_pair (first, first);
for (; first != last; ++first) {
if (*first < *r.first)
r.first = first;
if (*r.second < *first)
r.second = first;
}
return r;
}
template <typename ForwardIterator, typename Compare>
pair<ForwardIterator,ForwardIterator> minmax_element (ForwardIterator first, ForwardIterator last, Compare comp)
{
pair<ForwardIterator,ForwardIterator> r = make_pair (first, first);
for (; first != last; ++first) {
if (comp (*first, *r.first))
r.first = first;
if (comp (*r.second, *first))
r.second = first;
}
return r;
}
/// \brief Makes [first,middle) a part of the sorted array.
/// Contents of [middle,last) is undefined. This implementation just calls stable_sort.
/// \ingroup SortingAlgorithms
template <typename RandomAccessIterator>
inline void partial_sort (RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
partial_sort (first, middle, last, less<value_type>());
}
/// \brief Puts \p nth element into its sorted position.
/// In this implementation, the entire array is sorted. I can't think of any
/// use for it where the time gained would be useful.
/// \ingroup SortingAlgorithms
/// \ingroup SearchingAlgorithms
///
template <typename RandomAccessIterator>
inline void nth_element (RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last)
{
partial_sort (first, nth, last);
}
/// \brief Like partial_sort, but outputs to [result_first,result_last)
/// \ingroup SortingAlgorithms
template <typename InputIterator, typename RandomAccessIterator>
inline RandomAccessIterator partial_sort_copy (InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last)
{
typedef typename iterator_traits<InputIterator>::value_type value_type;
return partial_sort_copy (first, last, result_first, result_last, less<value_type>());
}
} // namespace ustl

View File

@ -0,0 +1,353 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "uutility.h"
#include <kstring.h>
namespace ustl {
#if HAVE_CPP11
template <typename T>
inline constexpr typename tm::RemoveReference<T>::Result&& move (T&& v) noexcept
{ return static_cast<typename tm::RemoveReference<T>::Result&&>(v); }
template <typename T>
inline constexpr T&& forward (typename tm::RemoveReference<T>::Result& v) noexcept
{ return static_cast<T&&>(v); }
template <typename T>
inline constexpr T&& forward (typename tm::RemoveReference<T>::Result&& v) noexcept
{ return static_cast<T&&>(v); }
#if HAVE_CPP14
template <typename T, typename U = T>
T exchange (T& a, U&& b)
{
T t = move(a);
a = forward<U>(b);
return t;
}
#endif
#else
template <typename T>
inline constexpr typename tm::RemoveReference<T>::Result& move (T& v) noexcept
{ return v; }
template <typename T>
inline constexpr T& forward (typename tm::RemoveReference<T>::Result& v) noexcept
{ return v; }
#endif
/// Assigns the contents of a to b and the contents of b to a.
/// This is used as a primitive operation by many other algorithms.
/// \ingroup SwapAlgorithms
///
template <typename T>
inline void swap (T& a, T& b)
{
typename tm::RemoveReference<T>::Result t = move(a);
a = move(b);
b = move(t);
}
/// Equivalent to swap (*a, *b)
/// \ingroup SwapAlgorithms
///
template <typename Iterator>
inline void iter_swap (Iterator a, Iterator b)
{
swap (*a, *b);
}
/// Copy copies elements from the range [first, last) to the range
/// [result, result + (last - first)). That is, it performs the assignments
/// *result = *first, *(result + 1) = *(first + 1), and so on. [1] Generally,
/// for every integer n from 0 to last - first, copy performs the assignment
/// *(result + n) = *(first + n). Assignments are performed in forward order,
/// i.e. in order of increasing n.
/// \ingroup MutatingAlgorithms
///
template <typename InputIterator, typename OutputIterator>
inline OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result)
{
for (; first != last; ++result, ++first)
*result = *first;
return result;
}
/// Copy_n copies elements from the range [first, first + n) to the range
/// [result, result + n). That is, it performs the assignments
/// *result = *first, *(result + 1) = *(first + 1), and so on. Generally,
/// for every integer i from 0 up to (but not including) n, copy_n performs
/// the assignment *(result + i) = *(first + i). Assignments are performed
/// in forward order, i.e. in order of increasing n.
/// \ingroup MutatingAlgorithms
///
template <typename InputIterator, typename OutputIterator>
inline OutputIterator copy_n (InputIterator first, size_t count, OutputIterator result)
{
for (; count; --count, ++result, ++first)
*result = *first;
return result;
}
/// \brief Copy copies elements from the range (last, first] to result.
/// \ingroup MutatingAlgorithms
/// Copies elements starting at last, decrementing both last and result.
///
template <typename InputIterator, typename OutputIterator>
inline OutputIterator copy_backward (InputIterator first, InputIterator last, OutputIterator result)
{
while (first != last)
*--result = *--last;
return result;
}
/// For_each applies the function object f to each element in the range
/// [first, last); f's return value, if any, is ignored. Applications are
/// performed in forward order, i.e. from first to last. For_each returns
/// the function object after it has been applied to each element.
/// \ingroup MutatingAlgorithms
///
template <typename InputIterator, typename UnaryFunction>
inline UnaryFunction for_each (InputIterator first, InputIterator last, UnaryFunction f)
{
for (; first != last; ++first)
f (*first);
return f;
}
/// Fill assigns the value value to every element in the range [first, last).
/// That is, for every iterator i in [first, last),
/// it performs the assignment *i = value.
/// \ingroup GeneratorAlgorithms
///
template <typename ForwardIterator, typename T>
inline void fill (ForwardIterator first, ForwardIterator last, const T& value)
{
for (; first != last; ++first)
*first = value;
}
/// Fill_n assigns the value value to every element in the range
/// [first, first+count). That is, for every iterator i in [first, first+count),
/// it performs the assignment *i = value. The return value is first + count.
/// \ingroup GeneratorAlgorithms
///
template <typename OutputIterator, typename T>
inline OutputIterator fill_n (OutputIterator first, size_t count, const T& value)
{
for (; count; --count, ++first)
*first = value;
return first;
}
#if __MMX__
extern "C" void copy_n_fast (const void* src, size_t count, void* dest) noexcept;
#else
inline void copy_n_fast (const void* src, size_t count, void* dest) noexcept
{ memmove (dest, src, count); }
#endif
#if __x86__
extern "C" void copy_backward_fast (const void* first, const void* last, void* result) noexcept;
#else
inline void copy_backward_fast (const void* first, const void* last, void* result) noexcept
{
const size_t nBytes (distance (first, last));
memmove (advance (result, -nBytes), first, nBytes);
}
#endif
extern "C" void fill_n8_fast (uint8_t* dest, size_t count, uint8_t v) noexcept;
extern "C" void fill_n16_fast (uint16_t* dest, size_t count, uint16_t v) noexcept;
extern "C" void fill_n32_fast (uint32_t* dest, size_t count, uint32_t v) noexcept;
extern "C" void rotate_fast (void* first, void* middle, void* last) noexcept;
#if __GNUC__ >= 4
/// \brief Computes the number of 1 bits in a number.
/// \ingroup ConditionAlgorithms
inline size_t popcount (uint32_t v) { return __builtin_popcount (v); }
#if HAVE_INT64_T
inline size_t popcount (uint64_t v) { return __builtin_popcountll (v); }
#endif
#else
size_t popcount (uint32_t v) noexcept;
#if HAVE_INT64_T
size_t popcount (uint64_t v) noexcept;
#endif // HAVE_INT64_T
#endif // __GNUC__
//----------------------------------------------------------------------
// Optimized versions for standard types
//----------------------------------------------------------------------
#if WANT_UNROLLED_COPY
template <typename T>
inline T* unrolled_copy (const T* first, size_t count, T* result)
{
copy_n_fast (first, count * sizeof(T), result);
return advance (result, count);
}
template <>
inline uint8_t* copy_backward (const uint8_t* first, const uint8_t* last, uint8_t* result)
{
copy_backward_fast (first, last, result);
return result;
}
template <typename T>
inline T* unrolled_fill (T* result, size_t count, T value)
{
for (; count; --count, ++result)
*result = value;
return result;
}
template <> inline uint8_t* unrolled_fill (uint8_t* result, size_t count, uint8_t value)
{ fill_n8_fast (result, count, value); return advance (result, count); }
template <> inline uint16_t* unrolled_fill (uint16_t* result, size_t count, uint16_t value)
{ fill_n16_fast (result, count, value); return advance (result, count); }
template <> inline uint32_t* unrolled_fill (uint32_t* result, size_t count, uint32_t value)
{ fill_n32_fast (result, count, value); return advance (result, count); }
/*template <> inline float* unrolled_fill (float* result, size_t count, float value)
{ fill_n32_fast (reinterpret_cast<uint32_t*>(result), count, *noalias_cast<uint32_t*>(&value)); return advance (result, count); }*/
#if __MMX__
#define UNROLLED_COPY_SPECIALIZATION(type) \
template <> inline type* copy (const type* first, const type* last, type* result) \
{ return unrolled_copy (first, distance (first, last), result); } \
template <> inline type* copy_n (const type* first, size_t count, type* result) \
{ return unrolled_copy (first, count, result); }
#define UNROLLED_FILL_SPECIALIZATION(type) \
template <> inline void fill (type* first, type* last, const type& value) \
{ unrolled_fill (first, distance (first, last), value); } \
template <> inline type* fill_n (type* first, size_t count, const type& value) \
{ return unrolled_fill (first, count, value); }
UNROLLED_COPY_SPECIALIZATION(uint8_t)
UNROLLED_FILL_SPECIALIZATION(uint8_t)
UNROLLED_COPY_SPECIALIZATION(uint16_t)
UNROLLED_FILL_SPECIALIZATION(uint16_t)
UNROLLED_COPY_SPECIALIZATION(uint32_t)
UNROLLED_FILL_SPECIALIZATION(uint32_t)
UNROLLED_COPY_SPECIALIZATION(float)
UNROLLED_FILL_SPECIALIZATION(float)
#undef UNROLLED_FILL_SPECIALIZATION
#undef UNROLLED_COPY_SPECIALIZATION
#endif // WANT_UNROLLED_COPY
#endif // __MMX__
// Specializations for void* and char*, aliasing the above optimized versions.
//
// All these need duplication with const and non-const arguments, since
// otherwise the compiler will default to the unoptimized version for
// pointers not const in the caller's context, such as local variables.
// These are all inline, but they sure slow down compilation... :(
//
#define COPY_ALIAS_FUNC(ctype, type, alias_type) \
template <> inline type* copy (ctype* first, ctype* last, type* result) \
{ return reinterpret_cast<type*> (copy (reinterpret_cast<const alias_type*>(first), reinterpret_cast<const alias_type*>(last), reinterpret_cast<alias_type*>(result))); }
#if WANT_UNROLLED_COPY
#if HAVE_THREE_CHAR_TYPES
COPY_ALIAS_FUNC(const char, char, uint8_t)
COPY_ALIAS_FUNC(char, char, uint8_t)
#endif
COPY_ALIAS_FUNC(const int8_t, int8_t, uint8_t)
COPY_ALIAS_FUNC(int8_t, int8_t, uint8_t)
COPY_ALIAS_FUNC(uint8_t, uint8_t, uint8_t)
COPY_ALIAS_FUNC(const int16_t, int16_t, uint16_t)
COPY_ALIAS_FUNC(int16_t, int16_t, uint16_t)
COPY_ALIAS_FUNC(uint16_t, uint16_t, uint16_t)
#if __MMX__ || (SIZE_OF_LONG > 4)
COPY_ALIAS_FUNC(const int32_t, int32_t, uint32_t)
COPY_ALIAS_FUNC(int32_t, int32_t, uint32_t)
COPY_ALIAS_FUNC(uint32_t, uint32_t, uint32_t)
#endif
#endif
COPY_ALIAS_FUNC(const void, void, uint8_t)
COPY_ALIAS_FUNC(void, void, uint8_t)
#undef COPY_ALIAS_FUNC
#define COPY_BACKWARD_ALIAS_FUNC(ctype, type, alias_type) \
template <> inline type* copy_backward (ctype* first, ctype* last, type* result) \
{ return reinterpret_cast<type*> (copy_backward (reinterpret_cast<const alias_type*>(first), reinterpret_cast<const alias_type*>(last), reinterpret_cast<alias_type*>(result))); }
#if WANT_UNROLLED_COPY
#if HAVE_THREE_CHAR_TYPES
COPY_BACKWARD_ALIAS_FUNC(char, char, uint8_t)
#endif
COPY_BACKWARD_ALIAS_FUNC(uint8_t, uint8_t, uint8_t)
COPY_BACKWARD_ALIAS_FUNC(int8_t, int8_t, uint8_t)
COPY_BACKWARD_ALIAS_FUNC(uint16_t, uint16_t, uint8_t)
COPY_BACKWARD_ALIAS_FUNC(const uint16_t, uint16_t, uint8_t)
COPY_BACKWARD_ALIAS_FUNC(int16_t, int16_t, uint8_t)
COPY_BACKWARD_ALIAS_FUNC(const int16_t, int16_t, uint8_t)
#endif
COPY_BACKWARD_ALIAS_FUNC(void, void, uint8_t)
COPY_BACKWARD_ALIAS_FUNC(const void, void, uint8_t)
#undef COPY_BACKWARD_ALIAS_FUNC
#define FILL_ALIAS_FUNC(type, alias_type, v_type) \
template <> inline void fill (type* first, type* last, const v_type& value) \
{ fill (reinterpret_cast<alias_type*>(first), reinterpret_cast<alias_type*>(last), alias_type(value)); }
FILL_ALIAS_FUNC(void, uint8_t, char)
FILL_ALIAS_FUNC(void, uint8_t, uint8_t)
#if WANT_UNROLLED_COPY
#if HAVE_THREE_CHAR_TYPES
FILL_ALIAS_FUNC(char, uint8_t, char)
FILL_ALIAS_FUNC(char, uint8_t, uint8_t)
#endif
FILL_ALIAS_FUNC(int8_t, uint8_t, int8_t)
FILL_ALIAS_FUNC(int16_t, uint16_t, int16_t)
#if __MMX__ || (SIZE_OF_LONG > 4)
FILL_ALIAS_FUNC(int32_t, uint32_t, int32_t)
#endif
#endif
#undef FILL_ALIAS_FUNC
#define COPY_N_ALIAS_FUNC(ctype, type, alias_type) \
template <> inline type* copy_n (ctype* first, size_t count, type* result) \
{ return reinterpret_cast<type*> (copy_n (reinterpret_cast<const alias_type*>(first), count, reinterpret_cast<alias_type*>(result))); }
COPY_N_ALIAS_FUNC(const void, void, uint8_t)
COPY_N_ALIAS_FUNC(void, void, uint8_t)
#if WANT_UNROLLED_COPY
#if HAVE_THREE_CHAR_TYPES
COPY_N_ALIAS_FUNC(const char, char, uint8_t)
COPY_N_ALIAS_FUNC(char, char, uint8_t)
#endif
COPY_N_ALIAS_FUNC(int8_t, int8_t, uint8_t)
COPY_N_ALIAS_FUNC(uint8_t, uint8_t, uint8_t)
COPY_N_ALIAS_FUNC(const int8_t, int8_t, uint8_t)
COPY_N_ALIAS_FUNC(int16_t, int16_t, uint16_t)
COPY_N_ALIAS_FUNC(uint16_t, uint16_t, uint16_t)
COPY_N_ALIAS_FUNC(const int16_t, int16_t, uint16_t)
#if __MMX__ || (SIZE_OF_LONG > 4)
COPY_N_ALIAS_FUNC(int32_t, int32_t, uint32_t)
COPY_N_ALIAS_FUNC(uint32_t, uint32_t, uint32_t)
COPY_N_ALIAS_FUNC(const int32_t, int32_t, uint32_t)
#endif
#endif
#undef COPY_N_ALIAS_FUNC
#define FILL_N_ALIAS_FUNC(type, alias_type, v_type) \
template <> inline type* fill_n (type* first, size_t n, const v_type& value) \
{ return reinterpret_cast<type*> (fill_n (reinterpret_cast<alias_type*>(first), n, alias_type(value))); }
FILL_N_ALIAS_FUNC(void, uint8_t, char)
FILL_N_ALIAS_FUNC(void, uint8_t, uint8_t)
#if WANT_UNROLLED_COPY
#if HAVE_THREE_CHAR_TYPES
FILL_N_ALIAS_FUNC(char, uint8_t, char)
FILL_N_ALIAS_FUNC(char, uint8_t, uint8_t)
#endif
FILL_N_ALIAS_FUNC(int8_t, uint8_t, int8_t)
FILL_N_ALIAS_FUNC(int16_t, uint16_t, int16_t)
#if __MMX__ || (SIZE_OF_LONG > 4)
FILL_N_ALIAS_FUNC(int32_t, uint32_t, int32_t)
#endif
#endif
#undef FILL_N_ALIAS_FUNC
extern const char _FmtPrtChr[2][8];
} // namespace ustl

View File

@ -0,0 +1,115 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2016 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "utypes.h"
#if HAVE_CPP11
//{{{ memory_order -----------------------------------------------------
namespace ustl {
enum memory_order {
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST
};
//}}}-------------------------------------------------------------------
//{{{ atomic
template <typename T>
class atomic {
T _v;
public:
atomic (void) = default;
inline constexpr atomic (T v) : _v(v) {}
atomic (const atomic&) = delete;
atomic& operator= (const atomic&) = delete;
inline bool is_lock_free (void) const
{ return __atomic_is_lock_free (sizeof(T), &_v); }
inline void store (T v, memory_order order = memory_order_seq_cst)
{ __atomic_store_n (&_v, v, order); }
inline T load (memory_order order = memory_order_seq_cst) const
{ return __atomic_load_n (&_v, order); }
inline T exchange (T v, memory_order order = memory_order_seq_cst)
{ return __atomic_exchange_n (&_v, v, order); }
inline bool compare_exchange_weak (T& expected, T desired, memory_order order = memory_order_seq_cst)
{ return __atomic_compare_exchange_n (&_v, &expected, desired, true, order, order); }
inline bool compare_exchange_weak (T& expected, T desired, memory_order success, memory_order failure)
{ return __atomic_compare_exchange_n (&_v, &expected, desired, true, success, failure); }
inline bool compare_exchange_strong (T& expected, T desired, memory_order success, memory_order failure)
{ return __atomic_compare_exchange_n (&_v, &expected, desired, false, success, failure); }
inline T fetch_add (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_fetch_add (&_v, v, order); }
inline T fetch_sub (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_fetch_sub (&_v, v, order); }
inline T fetch_and (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_fetch_and (&_v, v, order); }
inline T fetch_or (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_fetch_or (&_v, v, order); }
inline T fetch_xor (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_fetch_xor (&_v, v, order); }
inline T add_fetch (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_add_fetch (&_v, v, order); }
inline T sub_fetch (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_sub_fetch (&_v, v, order); }
inline T and_fetch (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_and_fetch (&_v, v, order); }
inline T or_fetch (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_or_fetch (&_v, v, order); }
inline T xor_fetch (T v, memory_order order = memory_order_seq_cst )
{ return __atomic_xor_fetch (&_v, v, order); }
inline operator T (void) const { return load(); }
inline T operator= (T v) { store(v); return v; }
inline T operator++ (int) { return fetch_add (1); }
inline T operator-- (int) { return fetch_sub (1); }
inline T operator++ (void) { return add_fetch (1); }
inline T operator-- (void) { return sub_fetch (1); }
inline T operator+= (T v) { return add_fetch (v); }
inline T operator-= (T v) { return sub_fetch (v); }
inline T operator&= (T v) { return and_fetch (v); }
inline T operator|= (T v) { return or_fetch (v); }
inline T operator^= (T v) { return xor_fetch (v); }
};
#define ATOMIC_VAR_INIT {0}
//}}}-------------------------------------------------------------------
//{{{ atomic_flag
class atomic_flag {
bool _v;
public:
atomic_flag (void) = default;
inline constexpr atomic_flag (bool v) : _v(v) {}
atomic_flag (const atomic_flag&) = delete;
atomic_flag& operator= (const atomic_flag&) = delete;
void clear (memory_order order = memory_order_seq_cst)
{ __atomic_clear (&_v, order); }
bool test_and_set (memory_order order = memory_order_seq_cst)
{ return __atomic_test_and_set (&_v, order); }
};
#define ATOMIC_FLAG_INIT {false}
//}}}-------------------------------------------------------------------
//{{{ fence functions
namespace {
template <typename T>
static inline T kill_dependency (T v) noexcept
{ T r (v); return r; }
static inline void atomic_thread_fence (memory_order order) noexcept
{ __atomic_thread_fence (order); }
static inline void atomic_signal_fence (memory_order order) noexcept
{ __atomic_signal_fence (order); }
} // namespace
} // namespace ustl
#endif // HAVE_CPP11
//}}}-------------------------------------------------------------------

View File

@ -0,0 +1,129 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "ustring.h"
#include "ufunction.h"
namespace ustl {
class istringstream;
typedef uint32_t bitset_value_type;
void convert_to_bitstring (const bitset_value_type* v, size_t n, string& buf) noexcept;
void convert_from_bitstring (const string& buf, bitset_value_type* v, size_t n) noexcept;
/// \class bitset ubitset.h ustl.h
/// \ingroup Sequences
///
/// \brief bitset is a fixed-size block of memory with addressable bits.
///
/// Normally used for state flags; allows setting and unsetting of individual
/// bits as well as bitwise operations on the entire set. The interface is
/// most like that of unsigned integers, and is intended to be used as such.
/// If you were using begin() and end() functions in STL's bitset, you would
/// not be able to do the same thing here, because those functions return
/// host type iterators, not bits.
///
template <size_t Size>
class bitset {
public:
typedef bitset_value_type value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef pointer iterator;
typedef const_pointer const_iterator;
typedef size_t difference_type;
typedef size_t size_type;
typedef const bitset<Size>& rcself_t;
private:
static const size_t s_WordBits = BitsInType (value_type);
static const size_t s_nWords = Size / s_WordBits + ((Size % s_WordBits) != 0);
static const size_t s_nBits = s_nWords * s_WordBits;
private:
inline value_type& BitRef (uoff_t n) { assert (n < Size); return _bits [n / s_WordBits]; }
inline value_type BitRef (uoff_t n) const { assert (n < Size); return _bits [n / s_WordBits]; }
inline value_type Mask (uoff_t n) const { assert (n < Size); return 1 << (n % s_WordBits); }
public:
inline bitset (value_type v = 0) { fill_n (_bits, s_nWords, 0); _bits[0] = v; }
inline bitset (const string& buf) { convert_from_bitstring (buf, _bits, s_nWords); }
inline void flip (uoff_t n) { BitRef(n) ^= Mask(n); }
inline void reset (void) { fill_n (_bits, s_nWords, 0); }
inline void clear (void) { fill_n (_bits, s_nWords, 0); }
inline void set (void) { fill_n (_bits, s_nWords, -1); }
inline bitset operator~ (void) const { bitset rv (*this); rv.flip(); return rv; }
inline size_type size (void) const { return Size; }
inline size_type capacity (void) const { return s_nBits; }
inline bool test (uoff_t n) const { return BitRef(n) & Mask(n); }
inline bool operator[] (uoff_t n) const { return test(n); }
inline const_iterator begin (void) const { return _bits; }
inline iterator begin (void) { return _bits; }
inline const_iterator end (void) const { return _bits + s_nWords; }
inline iterator end (void) { return _bits + s_nWords; }
/// Returns the value_type with the equivalent bits. If size() > 1, you'll get only the first BitsInType(value_type) bits.
inline value_type to_value (void) const { return _bits[0]; }
/// Flips all the bits in the set.
inline void flip (void) { transform (begin(), end(), begin(), bitwise_not<value_type>()); }
/// Sets or clears bit \p n.
inline void set (uoff_t n, bool val = true)
{
value_type& br (BitRef (n));
const value_type mask (Mask (n));
const value_type bOn (br | mask), bOff (br & ~mask);
br = val ? bOn : bOff;
}
// Sets the value of the bitrange \p first through \p last to the equivalent number of bits from \p v.
inline void set (uoff_t first, uoff_t DebugArg(last), value_type v)
{
assert (size_t (distance (first, last)) <= s_WordBits && "Bit ranges must be 32 bits or smaller");
assert (first / s_WordBits == last / s_WordBits && "Bit ranges can not cross dword (4 byte) boundary");
assert ((v & BitMask(value_type,distance(first,last))) == v && "The value is too large to fit in the given bit range");
BitRef(first) |= v << (first % s_WordBits);
}
/// Clears the bit \p n.
inline void reset (uoff_t n) { set (n, false); }
/// Returns a string with bits MSB "001101001..." LSB.
inline string to_string (void) const
{
string rv (Size, '0');
convert_to_bitstring (_bits, s_nWords, rv);
return rv;
}
inline value_type at (uoff_t n) const { return test(n); }
/// Returns the value in bits \p first through \p last.
inline value_type at (uoff_t first, uoff_t last) const
{
assert (size_t (distance (first, last)) <= s_WordBits && "Bit ranges must be 32 bits or smaller");
assert (first / s_WordBits == last / s_WordBits && "Bit ranges can not cross dword (4 byte) boundary");
return (BitRef(first) >> (first % s_WordBits)) & BitMask(value_type,distance(first, last));
}
inline bool any (void) const { value_type sum = 0; foreach (const_iterator, i, *this) sum |= *i; return sum; }
inline bool none (void) const { return !any(); }
inline size_t count (void) const { size_t sum = 0; foreach (const_iterator, i, *this) sum += popcount(*i); return sum; }
inline bool operator== (rcself_t v) const
{ return s_nWords == 1 ? (_bits[0] == v._bits[0]) : equal (begin(), end(), v.begin()); }
inline bitset operator& (rcself_t v) const
{ bitset<Size> result; transform (begin(), end(), v.begin(), result.begin(), bitwise_and<value_type>()); return result; }
inline bitset operator| (rcself_t v) const
{ bitset<Size> result; transform (begin(), end(), v.begin(), result.begin(), bitwise_or<value_type>()); return result; }
inline bitset operator^ (rcself_t v) const
{ bitset<Size> result; transform (begin(), end(), v.begin(), result.begin(), bitwise_xor<value_type>()); return result; }
inline rcself_t operator&= (rcself_t v)
{ transform (begin(), end(), v.begin(), begin(), bitwise_and<value_type>()); return *this; }
inline rcself_t operator|= (rcself_t v)
{ transform (begin(), end(), v.begin(), begin(), bitwise_or<value_type>()); return *this; }
inline rcself_t operator^= (rcself_t v)
{ transform (begin(), end(), v.begin(), begin(), bitwise_xor<value_type>()); return *this; }
inline void read (istream& is) { nr_container_read (is, *this); }
inline void write (ostream& os) const { nr_container_write (os, *this); }
inline void text_write (ostringstream& os) const { os << to_string(); }
void text_read (istringstream& is);
inline size_t stream_size (void) const { return sizeof(_bits); }
private:
value_type _bits [s_nWords];
};
} // namespace ustl

View File

@ -0,0 +1,467 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
namespace ustl {
/// Copy copies elements from the range [first, last) to the range
/// [result, result + (last - first)). That is, it performs the assignments
/// *result = *first, *(result + 1) = *(first + 1), and so on. [1] Generally,
/// for every integer n from 0 to last - first, copy performs the assignment
/// *(result + n) = *(first + n). Assignments are performed in forward order,
/// i.e. in order of increasing n.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator>
inline OutputIterator copy (const Container& ctr, OutputIterator result)
{
return copy (ctr.begin(), ctr.end(), result);
}
/// Copy_if copies elements from the range [first, last) to the range
/// [result, result + (last - first)) if pred(*i) returns true.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator, typename Predicate>
inline OutputIterator copy_if (Container& ctr, OutputIterator result, Predicate pred)
{
return copy_if (ctr.begin(), ctr.end(), result, pred);
}
/// For_each applies the function object f to each element in the range
/// [first, last); f's return value, if any, is ignored. Applications are
/// performed in forward order, i.e. from first to last. For_each returns
/// the function object after it has been applied to each element.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename UnaryFunction>
inline UnaryFunction for_each (Container& ctr, UnaryFunction f)
{
return for_each (ctr.begin(), ctr.end(), f);
}
/// For_each applies the function object f to each element in the range
/// [first, last); f's return value, if any, is ignored. Applications are
/// performed in forward order, i.e. from first to last. For_each returns
/// the function object after it has been applied to each element.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename UnaryFunction>
inline UnaryFunction for_each (const Container& ctr, UnaryFunction f)
{
return for_each (ctr.begin(), ctr.end(), f);
}
/// Returns the first iterator i in the range [first, last) such that
/// *i == value. Returns last if no such iterator exists.
/// \ingroup SearchingAlgorithms
///
template <typename Container, typename EqualityComparable>
inline typename Container::const_iterator find (const Container& ctr, const EqualityComparable& value)
{
return find (ctr.begin(), ctr.end(), value);
}
template <typename Container, typename EqualityComparable>
inline typename Container::iterator find (Container& ctr, const EqualityComparable& value)
{
return find (ctr.begin(), ctr.end(), value);
}
/// Returns the first iterator i in the range [first, last) such that
/// pred(*i) is true. Returns last if no such iterator exists.
/// \ingroup SearchingAlgorithms
///
template <typename Container, typename Predicate>
inline typename Container::const_iterator find_if (const Container& ctr, Predicate pred)
{
return find_if (ctr.begin(), ctr.end(), pred);
}
template <typename Container, typename Predicate>
inline typename Container::iterator find_if (Container& ctr, Predicate pred)
{
return find_if (ctr.begin(), ctr.end(), pred);
}
/// Count finds the number of elements in [first, last) that are equal
/// to value. More precisely, the first version of count returns the
/// number of iterators i in [first, last) such that *i == value.
/// \ingroup ConditionAlgorithms
///
template <typename Container, typename EqualityComparable>
inline size_t count (const Container& ctr, const EqualityComparable& value)
{
return count (ctr.begin(), ctr.end(), value);
}
/// Count_if finds the number of elements in [first, last) that satisfy the
/// predicate pred. More precisely, the first version of count_if returns the
/// number of iterators i in [first, last) such that pred(*i) is true.
/// \ingroup ConditionAlgorithms
///
template <typename Container, typename Predicate>
inline size_t count_if (const Container& ctr, Predicate pred)
{
return count_if (ctr.begin(), ctr.end(), pred);
}
/// The first version of transform performs the operation op(*i) for each
/// iterator i in the range [first, last), and assigns the result of that
/// operation to *o, where o is the corresponding output iterator. That is,
/// for each n such that 0 <= n < last - first, it performs the assignment
/// *(result + n) = op(*(first + n)).
/// The return value is result + (last - first).
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename UnaryFunction>
inline void transform (Container& ctr, UnaryFunction op)
{
transform (ctr.begin(), ctr.end(), ctr.begin(), op);
}
/// The first version of transform performs the operation op(*i) for each
/// iterator i in the range [first, last), and assigns the result of that
/// operation to *o, where o is the corresponding output iterator. That is,
/// for each n such that 0 <= n < last - first, it performs the assignment
/// *(result + n) = op(*(first + n)).
/// The return value is result + (last - first).
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator, typename UnaryFunction>
inline OutputIterator transform (Container& ctr, OutputIterator result, UnaryFunction op)
{
return transform (ctr.begin(), ctr.end(), result, op);
}
/// The second version of transform is very similar, except that it uses a
/// Binary Function instead of a Unary Function: it performs the operation
/// op(*i1, *i2) for each iterator i1 in the range [first1, last1) and assigns
/// the result to *o, where i2 is the corresponding iterator in the second
/// input range and where o is the corresponding output iterator. That is,
/// for each n such that 0 <= n < last1 - first1, it performs the assignment
/// *(result + n) = op(*(first1 + n), *(first2 + n).
/// The return value is result + (last1 - first1).
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename InputIterator, typename OutputIterator, typename BinaryFunction>
inline OutputIterator transform (Container& ctr, InputIterator first, OutputIterator result, BinaryFunction op)
{
return transform (ctr.begin(), ctr.end(), first, result, op);
}
/// Replace replaces every element in the range [first, last) equal to
/// old_value with new_value. That is: for every iterator i,
/// if *i == old_value then it performs the assignment *i = new_value.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename T>
inline void replace (Container& ctr, const T& old_value, const T& new_value)
{
replace (ctr.begin(), ctr.end(), old_value, new_value);
}
/// Replace_if replaces every element in the range [first, last) for which
/// pred returns true with new_value. That is: for every iterator i, if
/// pred(*i) is true then it performs the assignment *i = new_value.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename Predicate, typename T>
inline void replace_if (Container& ctr, Predicate pred, const T& new_value)
{
replace_if (ctr.begin(), ctr.end(), pred, new_value);
}
/// Replace_copy copies elements from the range [first, last) to the range
/// [result, result + (last-first)), except that any element equal to old_value
/// is not copied; new_value is copied instead. More precisely, for every
/// integer n such that 0 <= n < last-first, replace_copy performs the
/// assignment *(result+n) = new_value if *(first+n) == old_value, and
/// *(result+n) = *(first+n) otherwise.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator, typename T>
inline OutputIterator replace_copy (const Container& ctr, OutputIterator result, const T& old_value, const T& new_value)
{
return replace_copy (ctr.begin(), ctr.end(), result, old_value, new_value);
}
/// Replace_copy_if copies elements from the range [first, last) to the range
/// [result, result + (last-first)), except that any element for which pred is
/// true is not copied; new_value is copied instead. More precisely, for every
/// integer n such that 0 <= n < last-first, replace_copy_if performs the
/// assignment *(result+n) = new_value if pred(*(first+n)),
/// and *(result+n) = *(first+n) otherwise.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator, typename Predicate, typename T>
inline OutputIterator replace_copy_if (const Container& ctr, OutputIterator result, Predicate pred, const T& new_value)
{
return replace_copy_if (ctr.begin(), ctr.end(), result, pred, new_value);
}
/// Fill assigns the value value to every element in the range [first, last).
/// That is, for every iterator i in [first, last),
/// it performs the assignment *i = value.
/// \ingroup GeneratorAlgorithms
///
template <typename Container, typename T>
inline void fill (Container& ctr, const T& value)
{
fill (ctr.begin(), ctr.end(), value);
}
/// Generate assigns the result of invoking gen, a function object that
/// takes no arguments, to each element in the range [first, last).
/// \ingroup GeneratorAlgorithms
///
template <typename Container, typename Generator>
inline void generate (Container& ctr, Generator gen)
{
generate (ctr.begin(), ctr.end(), gen);
}
/// Randomly permute the elements of the container.
/// \ingroup GeneratorAlgorithms
///
template <typename Container>
inline void random_shuffle (Container& ctr)
{
random_shuffle (ctr.begin(), ctr.end());
}
/// Remove_copy copies elements that are not equal to value from the range
/// [first, last) to a range beginning at result. The return value is the
/// end of the resulting range. This operation is stable, meaning that the
/// relative order of the elements that are copied is the same as in the
/// range [first, last).
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator, typename T>
inline OutputIterator remove_copy (const Container& ctr, OutputIterator result, const T& value)
{
return remove_copy (ctr.begin(), ctr.end(), result, value);
}
/// Remove_copy_if copies elements from the range [first, last) to a range
/// beginning at result, except that elements for which pred is true are not
/// copied. The return value is the end of the resulting range. This operation
/// is stable, meaning that the relative order of the elements that are copied
/// is the same as in the range [first, last).
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator, typename Predicate>
inline OutputIterator remove_copy_if (const Container& ctr, OutputIterator result, Predicate pred)
{
return remove_copy_if (ctr.begin(), ctr.end(), result, pred);
}
/// Remove removes from the range [first, last) all elements that are equal to
/// value. That is, remove returns an iterator new_last such that the range
/// [first, new_last) contains no elements equal to value. Remove is stable,
/// meaning that the relative order of elements that are not equal to value is
/// unchanged.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename T>
inline void remove (Container& ctr, const T& value)
{
ctr.erase (remove_copy (ctr.begin(), ctr.end(), ctr.begin(), value), ctr.end());
}
/// Remove removes from the range [first, last) all elements that have an iterator
/// in range [rfirst, rlast). The range is assumed to be sorted. That is, remove
/// returns an iterator new_last such that the range [first, new_last) contains
/// no elements whose iterators are in [rfirst, rlast). Remove is stable,
/// meaning that the relative order of elements that are not equal to value is
/// unchanged. This version of the algorithm is a uSTL extension.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename ForwardIterator>
inline void remove (Container& ctr, ForwardIterator rfirst, ForwardIterator rlast)
{
ctr.erase (remove_copy (ctr.begin(), ctr.end(), ctr.begin(), rfirst, rlast), ctr.end());
}
/// Remove_if removes from the range [first, last) every element x such that
/// pred(x) is true. That is, remove_if returns an iterator new_last such that
/// the range [first, new_last) contains no elements for which pred is true.
/// The iterators in the range [new_last, last) are all still dereferenceable,
/// but the elements that they point to are unspecified. Remove_if is stable,
/// meaning that the relative order of elements that are not removed is
/// unchanged.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename Predicate>
inline void remove_if (Container& ctr, Predicate pred)
{
ctr.erase (remove_copy_if (ctr.begin(), ctr.end(), ctr.begin(), pred), ctr.end());
}
/// Unique_copy copies elements from the range [first, last) to a range
/// beginning with result, except that in a consecutive group of duplicate
/// elements only the first one is copied. The return value is the end of
/// the range to which the elements are copied. This behavior is similar
/// to the Unix filter uniq.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename OutputIterator>
inline OutputIterator unique_copy (const Container& ctr, OutputIterator result)
{
return unique_copy (ctr.begin(), ctr.end(), result);
}
/// Every time a consecutive group of duplicate elements appears in the range
/// [first, last), the algorithm unique removes all but the first element.
/// That is, unique returns an iterator new_last such that the range [first,
/// new_last) contains no two consecutive elements that are duplicates.
/// The iterators in the range [new_last, last) are all still dereferenceable,
/// but the elements that they point to are unspecified. Unique is stable,
/// meaning that the relative order of elements that are not removed is
/// unchanged.
/// \ingroup MutatingAlgorithms
///
template <typename Container>
inline void unique (Container& ctr)
{
ctr.erase (unique_copy (ctr.begin(), ctr.end(), ctr.begin()), ctr.end());
}
/// Every time a consecutive group of duplicate elements appears in the range
/// [first, last), the algorithm unique removes all but the first element.
/// That is, unique returns an iterator new_last such that the range [first,
/// new_last) contains no two consecutive elements that are duplicates.
/// The iterators in the range [new_last, last) are all still dereferenceable,
/// but the elements that they point to are unspecified. Unique is stable,
/// meaning that the relative order of elements that are not removed is
/// unchanged.
/// \ingroup MutatingAlgorithms
///
template <typename Container, typename BinaryPredicate>
inline void unique (Container& ctr, BinaryPredicate binary_pred)
{
ctr.erase (unique_copy (ctr.begin(), ctr.end(), ctr.begin(), binary_pred), ctr.end());
}
/// Reverse reverses a range.
/// That is: for every i such that 0 <= i <= (last - first) / 2),
/// it exchanges *(first + i) and *(last - (i + 1)).
/// \ingroup MutatingAlgorithms
///
template <typename Container>
inline void reverse (Container& ctr)
{
reverse (ctr.begin(), ctr.end());
}
/// Exchanges ranges [first, middle) and [middle, last)
/// \ingroup MutatingAlgorithms
///
template <typename Container>
inline void rotate (Container& ctr, off_t offset)
{
assert (size_t(offset > 0 ? offset : -offset) < ctr.size());
if (offset > 0)
rotate (ctr.begin(), ctr.end() - offset, ctr.end());
else
rotate (ctr.begin(), ctr.begin() - offset, ctr.end());
}
/// Returns the furthermost iterator i in [first, last) such that,
/// for every iterator j in [first, i), *j < value
/// Assumes the range is sorted.
/// \ingroup SearchingAlgorithms
///
template <typename Container, typename LessThanComparable>
inline typename Container::const_iterator lower_bound (const Container& ctr, const LessThanComparable& value)
{
return lower_bound (ctr.begin(), ctr.end(), value);
}
template <typename Container, typename LessThanComparable>
inline typename Container::iterator lower_bound (Container& ctr, const LessThanComparable& value)
{
return lower_bound (ctr.begin(), ctr.end(), value);
}
/// Returns the furthermost iterator i in [first,last) such that for
/// every iterator j in [first,i), value < *j is false.
/// \ingroup SearchingAlgorithms
///
template <typename Container, typename LessThanComparable>
inline typename Container::const_iterator upper_bound (const Container& ctr, const LessThanComparable& value)
{
return upper_bound (ctr.begin(), ctr.end(), value);
}
template <typename Container, typename LessThanComparable>
inline typename Container::iterator upper_bound (Container& ctr, const LessThanComparable& value)
{
return upper_bound (ctr.begin(), ctr.end(), value);
}
/// Performs a binary search for \p value.
/// Assumes the range is sorted.
/// \ingroup SearchingAlgorithms
///
template <typename Container>
inline bool binary_search (const Container& ctr, const typename Container::value_type& value)
{
return binary_search (ctr.begin(), ctr.end(), value);
}
template <typename Container>
inline bool binary_search (Container& ctr, const typename Container::value_type& value)
{
return binary_search (ctr.begin(), ctr.end(), value);
}
/// Returns pair<lower_bound,upper_bound>
/// \ingroup SearchingAlgorithms
///
template <typename Container, typename LessThanComparable>
inline pair<typename Container::const_iterator,typename Container::const_iterator> equal_range (const Container& ctr, const LessThanComparable& value)
{
return equal_range (ctr.begin(), ctr.end(), value);
}
template <typename Container, typename LessThanComparable>
inline pair<typename Container::iterator,typename Container::iterator> equal_range (Container& ctr, const LessThanComparable& value)
{
return equal_range (ctr.begin(), ctr.end(), value);
}
/// Sorts the container
/// \ingroup SortingAlgorithms
///
template <typename Container>
inline void sort (Container& ctr)
{
sort (ctr.begin(), ctr.end());
}
/// Sorts the container
/// \ingroup SortingAlgorithms
///
template <typename Container, typename Compare>
inline void sort (Container& ctr, Compare comp)
{
sort (ctr.begin(), ctr.end(), comp);
}
/// Sorts the container
/// \ingroup SortingAlgorithms
///
template <typename Container>
inline void stable_sort (Container& ctr)
{
stable_sort (ctr.begin(), ctr.end());
}
/// Sorts the container
/// \ingroup SortingAlgorithms
///
template <typename Container, typename Compare>
inline void stable_sort (Container& ctr, Compare comp)
{
stable_sort (ctr.begin(), ctr.end(), comp);
}
} // namespace ustl

View File

@ -0,0 +1,462 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
namespace ustl {
//----------------------------------------------------------------------
// Standard functors
//----------------------------------------------------------------------
/// \brief void-returning function abstract interface.
/// \ingroup FunctorObjects
template <typename Result>
struct void_function {
typedef Result result_type;
};
/// \brief \p Result f (\p Arg) function abstract interface.
/// \ingroup FunctorObjects
template <typename Arg, typename Result>
struct unary_function {
typedef Arg argument_type;
typedef Result result_type;
};
/// \brief \p Result f (\p Arg1, \p Arg2) function abstract interface.
/// \ingroup FunctorObjects
template <typename Arg1, typename Arg2, typename Result>
struct binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define STD_BINARY_FUNCTOR(name, rv, func) \
template <class T> struct name : public binary_function<T,T,rv> \
{ inline rv operator()(const T& a, const T& b) const { return func; } };
#define STD_UNARY_FUNCTOR(name, rv, func) \
template <class T> struct name : public unary_function<T,rv> \
{ inline rv operator()(const T& a) const { return func; } };
#define STD_CONVERSION_FUNCTOR(name, func) \
template <class S, class D> struct name : public unary_function<S,D> \
{ inline D operator()(const S& a) const { return func; } };
STD_BINARY_FUNCTOR (plus, T, (a + b))
STD_BINARY_FUNCTOR (minus, T, (a - b))
STD_BINARY_FUNCTOR (divides, T, (a / b))
STD_BINARY_FUNCTOR (modulus, T, (a % b))
STD_BINARY_FUNCTOR (multiplies, T, (a * b))
STD_BINARY_FUNCTOR (logical_and, T, (a && b))
STD_BINARY_FUNCTOR (logical_or, T, (a || b))
STD_UNARY_FUNCTOR (logical_not, T, (!a))
STD_BINARY_FUNCTOR (bitwise_or, T, (a | b))
STD_BINARY_FUNCTOR (bitwise_and, T, (a & b))
STD_BINARY_FUNCTOR (bitwise_xor, T, (a ^ b))
STD_UNARY_FUNCTOR (bitwise_not, T, (~a))
STD_UNARY_FUNCTOR (negate, T, (-a))
STD_BINARY_FUNCTOR (equal_to, bool, (a == b))
STD_BINARY_FUNCTOR (not_equal_to, bool, (!(a == b)))
STD_BINARY_FUNCTOR (greater, bool, (b < a))
STD_BINARY_FUNCTOR (less, bool, (a < b))
STD_BINARY_FUNCTOR (greater_equal, bool, (!(a < b)))
STD_BINARY_FUNCTOR (less_equal, bool, (!(b < a)))
STD_BINARY_FUNCTOR (compare, int, (a < b ? -1 : (b < a)))
STD_UNARY_FUNCTOR (identity, T, (a))
#endif // DOXYGEN_SHOULD_SKIP_THIS
/// \brief Selects and returns the first argument.
/// \ingroup FunctorObjects
template <class T1, class T2> struct project1st : public binary_function<T1,T2,T1> { inline const T1& operator()(const T1& a, const T2&) const { return a; } };
/// \brief Selects and returns the second argument.
/// \ingroup FunctorObjects
template <class T1, class T2> struct project2nd : public binary_function<T1,T2,T2> { inline const T2& operator()(const T1&, const T2& a) const { return a; } };
//----------------------------------------------------------------------
// Generic function to functor converters.
//----------------------------------------------------------------------
/// \brief Wrapper object for unary function pointers.
/// Use the ptr_fun accessor to create this object.
/// \ingroup FunctorObjects
template <typename Arg, typename Result>
class pointer_to_unary_function : public unary_function<Arg,Result> {
public:
typedef Arg argument_type;
typedef Result result_type;
typedef Result (*pfunc_t)(Arg);
public:
explicit inline pointer_to_unary_function (pfunc_t pfn) : _pfn (pfn) {}
inline result_type operator() (argument_type v) const { return _pfn(v); }
private:
pfunc_t _pfn; ///< Pointer to the wrapped function.
};
/// \brief Wrapper object for binary function pointers.
/// Use the ptr_fun accessor to create this object.
/// \ingroup FunctorObjects
template <typename Arg1, typename Arg2, typename Result>
class pointer_to_binary_function : public binary_function<Arg1,Arg2,Result> {
public:
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
typedef Result (*pfunc_t)(Arg1, Arg2);
public:
explicit inline pointer_to_binary_function (pfunc_t pfn) : _pfn (pfn) {}
inline result_type operator() (first_argument_type v1, second_argument_type v2) const { return _pfn(v1, v2); }
private:
pfunc_t _pfn; ///< Pointer to the wrapped function.
};
/// ptr_fun(pfn) wraps function pointer pfn into a functor class that calls it.
/// \ingroup FunctorAccessors
template <typename Arg, typename Result>
inline pointer_to_unary_function<Arg,Result> ptr_fun (Result (*pfn)(Arg))
{
return pointer_to_unary_function<Arg,Result> (pfn);
}
/// ptr_fun(pfn) wraps function pointer pfn into a functor class that calls it.
/// \ingroup FunctorAccessors
template <typename Arg1, typename Arg2, typename Result>
inline pointer_to_binary_function<Arg1,Arg2,Result> ptr_fun (Result (*pfn)(Arg1,Arg2))
{
return pointer_to_binary_function<Arg1,Arg2,Result> (pfn);
}
//----------------------------------------------------------------------
// Negators.
//----------------------------------------------------------------------
/// \brief Wraps a unary function to return its logical negative.
/// Use the unary_negator accessor to create this object.
/// \ingroup FunctorObjects
template <class UnaryFunction>
class unary_negate : public unary_function<typename UnaryFunction::argument_type,
typename UnaryFunction::result_type> {
public:
typedef typename UnaryFunction::argument_type argument_type;
typedef typename UnaryFunction::result_type result_type;
public:
explicit inline unary_negate (UnaryFunction pfn) : _pfn (pfn) {}
inline result_type operator() (argument_type v) const { return !_pfn(v); }
private:
UnaryFunction _pfn;
};
/// Returns the functor that negates the result of *pfn().
/// \ingroup FunctorAccessors
template <class UnaryFunction>
inline unary_negate<UnaryFunction> unary_negator (UnaryFunction pfn)
{
return unary_negate<UnaryFunction>(pfn);
}
//----------------------------------------------------------------------
// Argument binders
//----------------------------------------------------------------------
/// \brief Converts a binary function to a unary function
/// by binding a constant value to the first argument.
/// Use the bind1st accessor to create this object.
/// \ingroup FunctorObjects
template <class BinaryFunction>
class binder1st : public unary_function<typename BinaryFunction::second_argument_type,
typename BinaryFunction::result_type> {
public:
typedef typename BinaryFunction::first_argument_type arg1_t;
typedef typename BinaryFunction::second_argument_type arg2_t;
typedef typename BinaryFunction::result_type result_t;
public:
inline binder1st (const BinaryFunction& pfn, const arg1_t& v) : _pfn (pfn), _v(v) {}
inline result_t operator()(arg2_t v2) const { return _pfn (_v, v2); }
protected:
BinaryFunction _pfn;
arg1_t _v;
};
/// \brief Converts a binary function to a unary function
/// by binding a constant value to the second argument.
/// Use the bind2nd accessor to create this object.
/// \ingroup FunctorObjects
template <class BinaryFunction>
class binder2nd : public unary_function<typename BinaryFunction::first_argument_type,
typename BinaryFunction::result_type> {
public:
typedef typename BinaryFunction::first_argument_type arg1_t;
typedef typename BinaryFunction::second_argument_type arg2_t;
typedef typename BinaryFunction::result_type result_t;
public:
inline binder2nd (const BinaryFunction& pfn, const arg2_t& v) : _pfn (pfn), _v(v) {}
inline result_t operator()(arg1_t v1) const { return _pfn (v1, _v); }
protected:
BinaryFunction _pfn;
arg2_t _v;
};
/// Converts \p pfn into a unary function by binding the first argument to \p v.
/// \ingroup FunctorAccessors
template <typename BinaryFunction>
inline binder1st<BinaryFunction>
bind1st (BinaryFunction pfn, typename BinaryFunction::first_argument_type v)
{
return binder1st<BinaryFunction> (pfn, v);
}
/// Converts \p pfn into a unary function by binding the second argument to \p v.
/// \ingroup FunctorAccessors
template <typename BinaryFunction>
inline binder2nd<BinaryFunction>
bind2nd (BinaryFunction pfn, typename BinaryFunction::second_argument_type v)
{
return binder2nd<BinaryFunction> (pfn, v);
}
//----------------------------------------------------------------------
// Composition adapters
//----------------------------------------------------------------------
/// \brief Chains two unary functions together.
///
/// When f(x) and g(x) are composed, the result is function c(x)=f(g(x)).
/// Use the \ref compose1 accessor to create this object.
/// This template is an extension, implemented by SGI STL and uSTL.
/// \ingroup FunctorObjects
///
template <typename Operation1, typename Operation2>
class unary_compose : public unary_function<typename Operation2::argument_type,
typename Operation1::result_type> {
public:
typedef typename Operation2::argument_type arg_t;
typedef const arg_t& rcarg_t;
typedef typename Operation1::result_type result_t;
public:
inline unary_compose (const Operation1& f, const Operation2& g) : _f(f), _g(g) {}
inline result_t operator() (rcarg_t x) const { return _f(_g(x)); }
protected:
Operation1 _f; ///< f(x), if c(x) = f(g(x))
Operation2 _g; ///< g(x), if c(x) = f(g(x))
};
/// Creates a \ref unary_compose object whose function c(x)=f(g(x))
/// \ingroup FunctorAccessors
template <typename Operation1, typename Operation2>
inline unary_compose<Operation1, Operation2>
compose1 (const Operation1& f, const Operation2& g)
{ return unary_compose<Operation1,Operation2>(f, g); }
/// \brief Chains two unary functions through a binary function.
///
/// When f(x,y), g(x), and h(x) are composed, the result is function
/// c(x)=f(g(x),h(x)). Use the \ref compose2 accessor to create this
/// object. This template is an extension, implemented by SGI STL and uSTL.
/// \ingroup FunctorObjects
///
template <typename Operation1, typename Operation2, typename Operation3>
class binary_compose : public unary_function<typename Operation2::argument_type,
typename Operation1::result_type> {
public:
typedef typename Operation2::argument_type arg_t;
typedef const arg_t& rcarg_t;
typedef typename Operation1::result_type result_t;
public:
inline binary_compose (const Operation1& f, const Operation2& g, const Operation3& h) : _f(f), _g(g), _h(h) {}
inline result_t operator() (rcarg_t x) const { return _f(_g(x), _h(x)); }
protected:
Operation1 _f; ///< f(x,y), if c(x) = f(g(x),h(x))
Operation2 _g; ///< g(x), if c(x) = f(g(x),h(x))
Operation3 _h; ///< h(x), if c(x) = f(g(x),h(x))
};
/// Creates a \ref binary_compose object whose function c(x)=f(g(x),h(x))
/// \ingroup FunctorAccessors
template <typename Operation1, typename Operation2, typename Operation3>
inline binary_compose<Operation1, Operation2, Operation3>
compose2 (const Operation1& f, const Operation2& g, const Operation3& h)
{ return binary_compose<Operation1, Operation2, Operation3> (f, g, h); }
//----------------------------------------------------------------------
// Member function adaptors
//----------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define MEM_FUN_T(WrapperName, ClassName, ArgType, FuncType, CallType) \
template <typename Ret, class T> \
class ClassName : public unary_function<ArgType,Ret> { \
public: \
typedef Ret (T::*func_t) FuncType; \
public: \
explicit inline ClassName (func_t pf) : _pf (pf) {} \
inline Ret operator() (ArgType p) const { return (p CallType _pf)(); } \
private: \
func_t _pf; \
}; \
\
template <class Ret, typename T> \
inline ClassName<Ret,T> WrapperName (Ret (T::*pf) FuncType) \
{ \
return ClassName<Ret,T> (pf); \
}
MEM_FUN_T(mem_fun, mem_fun_t, T*, (void), ->*)
MEM_FUN_T(mem_fun, const_mem_fun_t, const T*, (void) const, ->*)
MEM_FUN_T(mem_fun_ref, mem_fun_ref_t, T&, (void), .*)
MEM_FUN_T(mem_fun_ref, const_mem_fun_ref_t, const T&, (void) const, .*)
#define EXT_MEM_FUN_T(ClassName, HostType, FuncType) \
template <class T, typename Ret, typename V> \
class ClassName : public unary_function<V,void> { \
public: \
typedef Ret (T::*func_t)(V) FuncType; \
public: \
inline ClassName (HostType t, func_t pf) : _t (t), _pf (pf) {} \
inline Ret operator() (V v) const { return (_t->*_pf)(v); } \
private: \
HostType _t; \
func_t _pf; \
}; \
\
template <class T, typename Ret, typename V> \
inline ClassName<T,Ret,V> mem_fun (HostType p, Ret (T::*pf)(V) FuncType) \
{ \
return ClassName<T,Ret,V> (p, pf); \
}
EXT_MEM_FUN_T(ext_mem_fun_t, T*, )
EXT_MEM_FUN_T(const_ext_mem_fun_t, const T*, const)
#endif // DOXYGEN_SHOULD_SKIP_THIS
//----------------------------------------------------------------------
// Member variable adaptors (uSTL extension)
//----------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define MEM_VAR_T(FunctorName, ArgType, VarType, BaseClass, CallImpl) \
template <typename Function, class T, typename VT> \
class FunctorName##_t : public BaseClass { \
public: \
typedef ArgType argument_type; \
typedef typename Function::result_type result_type; \
typedef VarType mem_var_ptr_t; \
public: \
inline FunctorName##_t (mem_var_ptr_t pv, Function pfn) : _pv(pv), _pfn(pfn) {} \
inline result_type operator() CallImpl \
private: \
mem_var_ptr_t _pv; \
Function _pfn; \
}; \
\
template <typename Function, class T, typename VT> \
inline FunctorName##_t<Function, T, VT> \
FunctorName (VT T::*mvp, Function pfn) \
{ \
return FunctorName##_t<Function,T,VT> (mvp, pfn); \
}
#define FUNCTOR_UNARY_BASE(ArgType) unary_function<ArgType, typename Function::result_type>
#define FUNCTOR_BINARY_BASE(ArgType) binary_function<ArgType, ArgType, typename Function::result_type>
#define MEM_VAR_UNARY_ARGS (argument_type p) const \
{ return _pfn(p.*_pv); }
#define MEM_VAR_BINARY_ARGS (argument_type p1, argument_type p2) const \
{ return _pfn(p1.*_pv, p2.*_pv); }
MEM_VAR_T(mem_var1, T&, VT T::*, FUNCTOR_UNARY_BASE(T&), MEM_VAR_UNARY_ARGS)
MEM_VAR_T(const_mem_var1, const T&, const VT T::*, FUNCTOR_UNARY_BASE(T&), MEM_VAR_UNARY_ARGS)
MEM_VAR_T(mem_var2, T&, VT T::*, FUNCTOR_BINARY_BASE(T&), MEM_VAR_BINARY_ARGS)
MEM_VAR_T(const_mem_var2, const T&, const VT T::*, FUNCTOR_BINARY_BASE(T&), MEM_VAR_BINARY_ARGS)
#undef MEM_VAR_UNARY_ARGS
#undef MEM_VAR_BINARY_ARGS
#endif // DOXYGEN_SHOULD_SKIP_THIS
/// Returned functor passes member variable \p mvp reference of given object to equal\<VT\>.
/// \ingroup FunctorAccessors
template <class T, typename VT>
inline const_mem_var1_t<binder2nd<equal_to<VT> >, T, VT>
mem_var_equal_to (const VT T::*mvp, const VT& v)
{
return const_mem_var1_t<binder2nd<equal_to<VT> >,T,VT> (mvp, bind2nd(equal_to<VT>(), v));
}
/// Returned functor passes member variable \p mvp reference of given object to less\<VT\>.
/// \ingroup FunctorAccessors
template <class T, typename VT>
inline const_mem_var1_t<binder2nd<less<VT> >, T, VT>
mem_var_less (const VT T::*mvp, const VT& v)
{
return const_mem_var1_t<binder2nd<less<VT> >,T,VT> (mvp, bind2nd(less<VT>(), v));
}
/// Returned functor passes member variable \p mvp reference of given object to equal\<VT\>.
/// \ingroup FunctorAccessors
template <class T, typename VT>
inline const_mem_var2_t<equal_to<VT>, T, VT>
mem_var_equal_to (const VT T::*mvp)
{
return const_mem_var2_t<equal_to<VT>,T,VT> (mvp, equal_to<VT>());
}
/// Returned functor passes member variable \p mvp reference of given object to less\<VT\>.
/// \ingroup FunctorAccessors
template <class T, typename VT>
inline const_mem_var2_t<less<VT>, T, VT>
mem_var_less (const VT T::*mvp)
{
return const_mem_var2_t<less<VT>,T,VT> (mvp, less<VT>());
}
//----------------------------------------------------------------------
// Dereference adaptors (uSTL extension)
//----------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define DEREFERENCER_T(ClassName, ArgType, BaseClass, CallImpl, FunctorKey) \
template <typename T, typename Function> \
class ClassName : public BaseClass { \
public: \
typedef ArgType* argument_type; \
typedef typename Function::result_type result_type; \
public: \
inline ClassName (Function pfn) : _pfn (pfn) {} \
inline result_type operator() CallImpl \
private: \
Function _pfn; \
}; \
\
template <typename T, typename Function> \
inline ClassName<T,Function> _dereference (Function pfn, FunctorKey) \
{ \
return ClassName<T,Function> (pfn); \
}
#define DEREF_UNARY_ARGS (argument_type p) const \
{ return _pfn(*p); }
#define DEREF_BINARY_ARGS (argument_type p1, argument_type p2) const \
{ return _pfn(*p1, *p2); }
DEREFERENCER_T(deref1_t, T, FUNCTOR_UNARY_BASE(T*), DEREF_UNARY_ARGS, FUNCTOR_UNARY_BASE(T))
DEREFERENCER_T(const_deref1_t, const T, FUNCTOR_UNARY_BASE(const T*), DEREF_UNARY_ARGS, FUNCTOR_UNARY_BASE(const T))
DEREFERENCER_T(deref2_t, T, FUNCTOR_BINARY_BASE(T*), DEREF_BINARY_ARGS, FUNCTOR_BINARY_BASE(T))
DEREFERENCER_T(const_deref2_t, const T, FUNCTOR_BINARY_BASE(const T*), DEREF_BINARY_ARGS, FUNCTOR_BINARY_BASE(const T))
#define dereference(f) _dereference(f,f)
#undef DEREF_UNARY_ARGS
#undef DEREF_BINARY_ARGS
#endif
} // namespace ustl

View File

@ -0,0 +1,161 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "ualgobase.h"
namespace ustl {
/// \brief Returns true if the given range is a heap under \p comp.
/// A heap is a sequentially encoded binary tree where for every node
/// comp(node,child1) is false and comp(node,child2) is false.
/// \ingroup HeapAlgorithms
/// \ingroup ConditionAlgorithms
///
template <typename RandomAccessIterator, typename Compare>
bool is_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
{
RandomAccessIterator iChild (first);
for (; ++iChild < last; ++first)
if (comp (*first, *iChild) || (++iChild < last && comp (*first, *iChild)))
return false;
return true;
}
/// Utility function to "trickle down" the root item - swaps the root item with its
/// largest child and recursively fixes the proper subtree.
template <typename RandomAccessIterator, typename Compare>
void trickle_down_heap (RandomAccessIterator first, size_t iHole, size_t heapSize, Compare comp)
{
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
const value_type v (first[iHole]);
for (size_t iChild; (iChild = 2 * iHole + 1) < heapSize;) {
if (iChild + 1 < heapSize)
iChild += comp (first[iChild], first[iChild + 1]);
if (comp (v, first[iChild])) {
first[iHole] = first[iChild];
iHole = iChild;
} else
break;
}
first[iHole] = v;
}
/// \brief make_heap turns the range [first, last) into a heap
/// At completion, is_heap (first, last, comp) is true.
/// The algorithm is adapted from "Classic Data Structures in C++" by Timothy Budd.
/// \ingroup HeapAlgorithms
/// \ingroup SortingAlgorithms
///
template <typename RandomAccessIterator, typename Compare>
void make_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
{
if (last <= first)
return;
const size_t heapSize = distance (first, last);
for (RandomAccessIterator i = first + (heapSize - 1)/2; i >= first; --i)
trickle_down_heap (first, distance(first,i), heapSize, comp);
}
/// \brief Inserts the *--last into the preceeding range assumed to be a heap.
/// \ingroup HeapAlgorithms
/// \ingroup MutatingAlgorithms
template <typename RandomAccessIterator, typename Compare>
void push_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
{
if (last <= first)
return;
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type;
const value_type v (*--last);
while (first < last) {
RandomAccessIterator iParent = first + (distance(first, last) - 1) / 2;
if (comp (v, *iParent))
break;
*last = *iParent;
last = iParent;
}
*last = v;
}
/// Removes the largest element from the heap (*first) and places it at *(last-1)
/// [first, last-1) is a heap after this operation.
/// \ingroup HeapAlgorithms
/// \ingroup MutatingAlgorithms
template <typename RandomAccessIterator, typename Compare>
void pop_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
{
if (--last <= first)
return;
iter_swap (first, last);
trickle_down_heap (first, 0, distance(first,last), comp);
}
/// Sorts heap [first, last) in descending order according to comp.
/// \ingroup HeapAlgorithms
/// \ingroup SortingAlgorithms
template <typename RandomAccessIterator, typename Compare>
void sort_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp)
{
for (; first < last; --last)
pop_heap (first, last, comp);
}
#define HEAP_FN_WITH_LESS(rtype, name) \
template <typename RandomAccessIterator>\
inline rtype name (RandomAccessIterator first, RandomAccessIterator last) \
{ \
typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; \
return name (first, last, less<value_type>()); \
}
HEAP_FN_WITH_LESS (bool, is_heap)
HEAP_FN_WITH_LESS (void, make_heap)
HEAP_FN_WITH_LESS (void, push_heap)
HEAP_FN_WITH_LESS (void, pop_heap)
HEAP_FN_WITH_LESS (void, sort_heap)
#undef HEAP_FN_WITH_LESS
/// \class priority_queue uheap.h ustl.h
/// \ingroup Sequences
///
/// \brief Sorted queue adapter to uSTL containers.
///
/// Acts just like the queue adapter, but keeps the elements sorted by priority
/// specified by the given comparison operator.
///
template <typename T, typename Container = vector<T>, typename Comp = less<typename Container::value_type> >
class priority_queue {
public:
typedef Container container_type;
typedef typename container_type::size_type size_type;
typedef typename container_type::value_type value_type;
typedef typename container_type::reference reference;
typedef typename container_type::const_reference const_reference;
typedef typename container_type::const_iterator const_iterator;
public:
inline explicit priority_queue (const Comp& c = Comp()) : _v(), _c(c) {}
inline priority_queue (const Comp& c, const container_type& v) : _v(v), _c(c) {}
priority_queue (const_iterator f, const_iterator l, const Comp& c = Comp())
: _v(f, l), _c(c) { make_heap (_v.begin(), _v.end(), _c); }
inline size_type size (void) const { return _v.size(); }
inline bool empty (void) const { return _v.empty(); }
inline const_reference top (void) const { return _v.front(); }
inline void push (const_reference v){ _v.push_back (v); push_heap (_v.begin(), _v.end(), _c); }
inline void pop (void) { pop_heap (_v.begin(), _v.end()); _v.pop_back(); }
inline void swap (priority_queue& v){ _v.swap (v._v); swap (_c, v._c); }
#if HAVE_CPP11
inline explicit priority_queue (priority_queue&& v) : _v(move(v._v)),_c(v._c) {}
inline priority_queue (const Comp& c, container_type&& v) : _v(move(v)),_c(c) {}
priority_queue (const_iterator f, const_iterator l, const Comp& c, container_type&& v)
: _v(move(v)), _c(c) { _v.insert (_v.end(), f, l); make_heap (_v.begin(), _v.end(), _c); }
inline priority_queue& operator= (priority_queue&& v) { swap (v); return *this; }
template <typename... Args>
inline void emplace (Args&&... args) { _v.emplace_back (forward<Args>(args)...); push_heap (_v.begin(), _v.end(), _c); }
#endif
private:
container_type _v; ///< Element container.
Comp _c; ///< Comparison functor by value.
};
} // namespace ustl

View File

@ -0,0 +1,99 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "utypes.h"
namespace ustl {
class file_exception;
/// Defines types and constants used by all stream classes.
class ios_base {
public:
/// Used to set parameters for stringstreams
enum fmtflags_bits {
boolalpha = (1 << 0), ///< Boolean values printed as text.
showbase = (1 << 1), ///< Add 0x or 0 prefixes on hex and octal numbers.
showpoint = (1 << 2), ///< Print decimal point.
showpos = (1 << 3),
skipws = (1 << 4), ///< Skip whitespace when reading.
unitbuf = (1 << 5),
uppercase = (1 << 6),
dec = (1 << 7), ///< Decimal number output.
oct = (1 << 8), ///< Octal number output.
hex = (1 << 9), ///< Hexadecimal number output.
fixed = (1 << 10), ///< Fixed-point float output.
scientific = (1 << 11), ///< Scientific float format.
left = (1 << 12), ///< Left alignment.
right = (1 << 13), ///< Right alignment.
internal = (1 << 14),
basefield = dec| oct| hex,
floatfield = fixed| scientific,
adjustfield = left| right| internal
};
/// For file-based streams, specifies fd mode.
enum openmode_bits {
in = (1 << 0),
out = (1 << 1),
app = (1 << 2),
ate = (1 << 3),
binary = (1 << 4),
trunc = (1 << 5),
#ifndef DOXYGEN_SHOULD_SKIP_THIS
nonblock= (1 << 6),
nocreate= (1 << 7),
noctty = (1 << 8),
nombits = 9
#endif
};
/// Seek directions, equivalent to SEEK_SET, SEEK_CUR, and SEEK_END.
enum seekdir {
beg,
cur,
end
};
/// I/O state bitmasks.
enum iostate_bits {
goodbit = 0,
badbit = (1 << 0),
eofbit = (1 << 1),
failbit = (1 << 2),
#ifndef DOXYGEN_SHOULD_SKIP_THIS
nbadbits = 3,
allbadbits = 0x7
#endif
};
enum { default_stream_buffer_size = 4095 };
typedef uint32_t openmode; ///< Holds openmode_bits.
struct fmtflags{ fmtflags(const uint32_t& flags) : f(flags){}; fmtflags() = default; uint32_t f; }; ///< Holds fmtflags_bits for a string stream.
typedef uint32_t iostate; ///< Holds iostate_bits for a file stream.
typedef file_exception failure; ///< Thrown by fstream on errors.
static const char c_DefaultDelimiters [16]; ///< Default word delimiters for stringstreams.
public:
inline ios_base (void) : _state (goodbit), _exceptions (allbadbits) {}
inline iostate rdstate (void) const { return _state; }
inline bool bad (void) const { return rdstate() & badbit; }
inline bool good (void) const { return rdstate() == goodbit; }
inline bool fail (void) const { return rdstate() & (badbit | failbit); }
inline bool eof (void) const { return rdstate() & eofbit; }
inline bool operator! (void) const { return fail(); }
inline operator bool (void) const { return !fail(); }
inline void clear (iostate v = goodbit) { _state = v; }
inline void setstate (iostate v) { _state |= v; }
inline iostate exceptions (void) const { return _exceptions; }
inline iostate exceptions (iostate v) { return _exceptions = v; }
protected:
inline bool set_and_throw (iostate v) { setstate(v); return exceptions() & v; }
void overrun (const char* op, const char* type, uint32_t n, uint32_t p, uint32_t rem);
private:
uint16_t _state; ///< Open state, using ios::iostate_bits.
uint16_t _exceptions; ///< Exception flags, using ios::iostate_bits.
};
} // namespace ustl

View File

@ -0,0 +1,82 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "sostream.h"
namespace ustl {
class ios : public ios_base {
public:
/// \class align uiosfunc.h ustl.h
/// \ingroup StreamFunctors
/// \brief Stream functor to allow inline align() calls.
///
/// Example: os << ios::align(sizeof(uint16_t));
///
class align {
public:
inline explicit align (size_t grain = c_DefaultAlignment) : _grain(grain) {}
inline istream& apply (istream& is) const { is.align (_grain); return is; }
inline ostream& apply (ostream& os) const { os.align (_grain); return os; }
inline void read (istream& is) const { apply (is); }
inline void write (ostream& os) const { apply (os); }
inline size_t stream_size (void) const { return _grain - 1; }
private:
const size_t _grain;
};
/// \class talign uiosfunc.h ustl.h
/// \ingroup StreamFunctors
/// \brief Stream functor to allow type-based alignment.
template <typename T>
class talign : public align {
public:
inline explicit talign (void) : align (stream_align_of (NullValue<T>())) {}
};
/// \class skip uiosfunc.h ustl.h
/// \ingroup StreamFunctors
/// \brief Stream functor to allow inline skip() calls.
///
/// Example: os << ios::skip(sizeof(uint16_t));
///
class skip {
public:
inline explicit skip (size_t nBytes) : _nBytes(nBytes) {}
inline istream& apply (istream& is) const { is.skip (_nBytes); return is; }
inline ostream& apply (ostream& os) const { os.skip (_nBytes); return os; }
inline void read (istream& is) const { apply (is); }
inline void write (ostream& os) const { apply (os); }
inline size_t stream_size (void) const { return _nBytes; }
private:
const size_t _nBytes;
};
/// \class width uiosfunc.h ustl.h
/// \ingroup StreamFunctors
/// \brief Stream functor to allow inline set_width() calls.
///
/// Example: os << ios::width(15);
///
class width {
public:
inline explicit width (size_t nBytes) : _nBytes(nBytes) {}
inline ostringstream& apply (ostringstream& os) const { os.width (_nBytes); return os; }
inline void text_write (ostringstream& os) const { apply (os); }
private:
const size_t _nBytes;
};
// Deprecated way to set output format base. Use setiosflags manipulator instead.
struct base {
inline explicit base (size_t n) : _f (n == 16 ? hex : (n == 8 ? oct : dec)) {}
inline void text_write (ostringstream& os) const { os.setf (_f, basefield); }
private:
fmtflags _f;
};
};
} // namespace ustl

View File

@ -0,0 +1,13 @@
#pragma once
#include "sostream.h"
#include "mistream.h"
#include "outerrstream.h"
namespace ustl
{
extern coutclass& cout;
extern coutclass& cerr;
}

View File

@ -0,0 +1,360 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
//
/// \file uiterator.h
/// \brief Contains various iterator adapters.
#pragma once
#include "utypes.h"
namespace ustl {
//----------------------------------------------------------------------
template <typename Category, typename T, typename Distance = ptrdiff_t, typename Pointer = T*, typename Reference = T&>
struct iterator {
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
typedef Category iterator_category;
};
//----------------------------------------------------------------------
struct input_iterator_tag {};
struct output_iterator_tag {};
struct forward_iterator_tag {};
struct bidirectional_iterator_tag {};
struct random_access_iterator_tag {};
/// \struct iterator_traits uiterator.h ustl.h
/// \brief Contains the type traits of \p Iterator
///
template <typename Iterator>
struct iterator_traits {
typedef typename Iterator::value_type value_type;
typedef typename Iterator::difference_type difference_type;
typedef typename Iterator::pointer pointer;
typedef typename Iterator::reference reference;
typedef typename Iterator::iterator_category iterator_category;
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <typename T>
struct iterator_traits<T*> {
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* const_pointer;
typedef T* pointer;
typedef const T& const_reference;
typedef T& reference;
typedef random_access_iterator_tag iterator_category;
};
template <typename T>
struct iterator_traits<const T*> {
typedef T value_type;
typedef ptrdiff_t difference_type;
typedef const T* const_pointer;
typedef const T* pointer;
typedef const T& const_reference;
typedef const T& reference;
typedef random_access_iterator_tag iterator_category;
};
template <>
struct iterator_traits<void*> {
typedef uint8_t value_type;
typedef ptrdiff_t difference_type;
typedef const void* const_pointer;
typedef void* pointer;
typedef const value_type& const_reference;
typedef value_type& reference;
typedef random_access_iterator_tag iterator_category;
};
template <>
struct iterator_traits<const void*> {
typedef uint8_t value_type;
typedef ptrdiff_t difference_type;
typedef const void* const_pointer;
typedef const void* pointer;
typedef const value_type& const_reference;
typedef const value_type& reference;
typedef random_access_iterator_tag iterator_category;
};
#endif
//----------------------------------------------------------------------
/// \class reverse_iterator uiterator.h ustl.h
/// \ingroup IteratorAdaptors
/// \brief Wraps \p Iterator to behave in an exactly opposite manner.
///
template <typename Iterator>
class reverse_iterator {
public:
typedef typename iterator_traits<Iterator>::value_type value_type;
typedef typename iterator_traits<Iterator>::difference_type difference_type;
typedef typename iterator_traits<Iterator>::pointer pointer;
typedef typename iterator_traits<Iterator>::reference reference;
typedef typename iterator_traits<Iterator>::iterator_category iterator_category;
public:
reverse_iterator (void) : _i() {}
explicit reverse_iterator (Iterator iter) : _i (iter) {}
inline bool operator== (const reverse_iterator& iter) const { return _i == iter._i; }
inline bool operator< (const reverse_iterator& iter) const { return iter._i < _i; }
inline Iterator base (void) const { return _i; }
inline reference operator* (void) const { Iterator prev (_i); --prev; return *prev; }
inline pointer operator-> (void) const { return &(operator*()); }
inline reverse_iterator& operator++ (void) { -- _i; return *this; }
inline reverse_iterator& operator-- (void) { ++ _i; return *this; }
inline reverse_iterator operator++ (int) { reverse_iterator prev (*this); -- _i; return prev; }
inline reverse_iterator operator-- (int) { reverse_iterator prev (*this); ++ _i; return prev; }
inline reverse_iterator& operator+= (size_t n) { _i -= n; return *this; }
inline reverse_iterator& operator-= (size_t n) { _i += n; return *this; }
inline reverse_iterator operator+ (size_t n) const { return reverse_iterator (_i - n); }
inline reverse_iterator operator- (size_t n) const { return reverse_iterator (_i + n); }
inline reference operator[] (uoff_t n) const { return *(*this + n); }
inline difference_type operator- (const reverse_iterator& i) const { return distance (i._i, _i); }
protected:
Iterator _i;
};
template <typename Iterator>
inline reverse_iterator<Iterator> make_reverse_iterator (Iterator i)
{ return reverse_iterator<Iterator>(i); }
//----------------------------------------------------------------------
#if HAVE_CPP11
/// \class move_iterator uiterator.h ustl.h
/// \ingroup IteratorAdaptors
/// \brief Wraps \p Iterator to behave in an exactly opposite manner.
///
template <typename Iterator>
class move_iterator {
public:
using value_type = typename iterator_traits<Iterator>::value_type;
using difference_type = typename iterator_traits<Iterator>::difference_type;
using pointer = typename iterator_traits<Iterator>::pointer;
using reference = value_type&&;
using iterator_category = typename iterator_traits<Iterator>::iterator_category;
public:
move_iterator (void) : _i() {}
explicit move_iterator (Iterator iter) : _i (iter) {}
inline bool operator== (const move_iterator& iter) const { return _i == iter._i; }
inline bool operator< (const move_iterator& iter) const { return _i < iter._i; }
inline Iterator base (void) const { return _i; }
inline reference operator* (void) const { return move(*_i); }
inline pointer operator-> (void) const { return &*_i; }
inline move_iterator& operator++ (void) { ++_i; return *this; }
inline move_iterator& operator-- (void) { --_i; return *this; }
inline move_iterator operator++ (int) { move_iterator r (*this); ++ _i; return r; }
inline move_iterator operator-- (int) { move_iterator r (*this); -- _i; return r; }
inline move_iterator& operator+= (size_t n) { _i += n; return *this; }
inline move_iterator& operator-= (size_t n) { _i -= n; return *this; }
inline move_iterator operator+ (size_t n) const { return move_iterator (_i - n); }
inline move_iterator operator- (size_t n) const { return move_iterator (_i + n); }
inline reference operator[] (uoff_t n) const { return move(*(*this + n)); }
inline difference_type operator- (const move_iterator& i) const { return distance (_i, i._i); }
protected:
Iterator _i;
};
template <typename Iterator>
inline move_iterator<Iterator> make_move_iterator (Iterator i)
{ return move_iterator<Iterator>(i); }
#endif
//----------------------------------------------------------------------
/// \class insert_iterator uiterator.h ustl.h
/// \ingroup IteratorAdaptors
/// \brief Calls insert on bound container for each assignment.
///
template <typename Container>
class insert_iterator {
public:
typedef typename Container::value_type value_type;
typedef typename Container::difference_type difference_type;
typedef typename Container::pointer pointer;
typedef typename Container::reference reference;
typedef typename Container::iterator iterator;
typedef output_iterator_tag iterator_category;
public:
explicit insert_iterator (Container& ctr, iterator ip) : _rctr (ctr), _ip (ip) {}
inline insert_iterator& operator= (typename Container::const_reference v)
{ _ip = _rctr.insert (_ip, v); return *this; }
inline insert_iterator& operator* (void) { return *this; }
inline insert_iterator& operator++ (void) { ++ _ip; return *this; }
inline insert_iterator operator++ (int) { insert_iterator prev (*this); ++_ip; return prev; }
protected:
Container& _rctr;
iterator _ip;
};
/// Returns the insert_iterator for \p ctr.
template <typename Container>
inline insert_iterator<Container> inserter (Container& ctr, typename Container::iterator ip)
{ return insert_iterator<Container> (ctr, ip); }
//----------------------------------------------------------------------
/// \class back_insert_iterator uiterator.h ustl.h
/// \ingroup IteratorAdaptors
/// \brief Calls push_back on bound container for each assignment.
///
template <class Container>
class back_insert_iterator {
public:
typedef typename Container::value_type value_type;
typedef typename Container::difference_type difference_type;
typedef typename Container::pointer pointer;
typedef typename Container::reference reference;
typedef output_iterator_tag iterator_category;
public:
explicit back_insert_iterator (Container& ctr) : _rctr (ctr) {}
inline back_insert_iterator& operator= (typename Container::const_reference v)
{ _rctr.push_back (v); return *this; }
inline back_insert_iterator& operator* (void) { return *this; }
inline back_insert_iterator& operator++ (void) { return *this; }
inline back_insert_iterator operator++ (int) { return *this; }
protected:
Container& _rctr;
};
/// Returns the back_insert_iterator for \p ctr.
template <class Container>
inline back_insert_iterator<Container> back_inserter (Container& ctr)
{ return back_insert_iterator<Container> (ctr); }
//----------------------------------------------------------------------
/// \class front_insert_iterator uiterator.h ustl.h
/// \ingroup IteratorAdaptors
/// \brief Calls push_front on bound container for each assignment.
///
template <class Container>
class front_insert_iterator {
public:
typedef typename Container::value_type value_type;
typedef typename Container::difference_type difference_type;
typedef typename Container::pointer pointer;
typedef typename Container::reference reference;
typedef output_iterator_tag iterator_category;
public:
explicit front_insert_iterator (Container& ctr) : _rctr (ctr) {}
inline front_insert_iterator& operator= (typename Container::const_reference v)
{ _rctr.push_front (v); return *this; }
inline front_insert_iterator& operator* (void) { return *this; }
inline front_insert_iterator& operator++ (void) { return *this; }
inline front_insert_iterator operator++ (int) { return *this; }
protected:
Container& _rctr;
};
/// Returns the front_insert_iterator for \p ctr.
template <class Container>
inline front_insert_iterator<Container> front_inserter (Container& ctr)
{ return front_insert_iterator<Container> (ctr); }
//----------------------------------------------------------------------
/// \class index_iterate uiterator.h ustl.h
/// \ingroup IteratorAdaptors
///
/// \brief Allows iteration through an index container.
///
/// Converts an iterator into a container of uoff_t indexes to an
/// iterator of iterators into another container.
///
template <typename RandomAccessIterator, typename IndexIterator>
class index_iterate {
public:
typedef RandomAccessIterator value_type;
typedef ptrdiff_t difference_type;
typedef RandomAccessIterator* pointer;
typedef RandomAccessIterator reference;
typedef random_access_iterator_tag iterator_category;
public:
index_iterate (void) : _base(), _i() {}
index_iterate (RandomAccessIterator ibase, IndexIterator iindex) : _base (ibase), _i (iindex) {}
inline bool operator== (const index_iterate& i) const { return _i == i._i; }
inline bool operator< (const index_iterate& i) const { return _i < i._i; }
inline bool operator== (const RandomAccessIterator& i) const { return _base == i; }
inline bool operator< (const RandomAccessIterator& i) const { return _base < i; }
inline IndexIterator base (void) const { return _i; }
inline reference operator* (void) const { return advance(_base, *_i); }
inline pointer operator-> (void) const { return &(operator*()); }
inline index_iterate& operator++ (void) { ++_i; return *this; }
inline index_iterate& operator-- (void) { --_i; return *this; }
inline index_iterate operator++ (int) { index_iterate prev (*this); ++_i; return prev; }
inline index_iterate operator-- (int) { index_iterate prev (*this); --_i; return prev; }
inline index_iterate& operator+= (size_t n) { _i += n; return *this; }
inline index_iterate& operator-= (size_t n) { _i -= n; return *this; }
inline index_iterate operator+ (size_t n) const { return index_iterate (_base, _i + n); }
inline index_iterate operator- (size_t n) const { return index_iterate (_base, _i - n); }
inline reference operator[] (uoff_t n) const { return *(*this + n); }
inline difference_type operator- (const index_iterate& i) const { return distance (_i, i._i); }
private:
RandomAccessIterator _base;
IndexIterator _i;
};
/// Returns an index_iterate for \p ibase over \p iindex.
template <typename RandomAccessIterator, typename IndexIterator>
inline index_iterate<RandomAccessIterator, IndexIterator> index_iterator (RandomAccessIterator ibase, IndexIterator iindex)
{
return index_iterate<RandomAccessIterator, IndexIterator> (ibase, iindex);
}
/// Converts the indexes in \p xc to iterators in \p ic of base \p ibase.
template <typename IndexContainer, typename IteratorContainer>
inline void indexv_to_iteratorv (typename IteratorContainer::value_type ibase, const IndexContainer& xc, IteratorContainer& ic)
{
ic.resize (xc.size());
copy_n (index_iterator (ibase, xc.begin()), xc.size(), ic.begin());
}
//----------------------------------------------------------------------
/// Converts the given const_iterator into an iterator.
///
template <typename Container>
inline typename Container::iterator unconst (typename Container::const_iterator i, Container&)
{ return const_cast<typename Container::iterator>(i); }
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#define IBYI(Iter1, Iter2, Ctr1, Ctr2) \
template <typename Container1, typename Container2> \
inline typename Container2::Iter2 ibyi (typename Container1::Iter1 idx, Ctr1& ctr1, Ctr2& ctr2) \
{ \
assert (ctr1.size() == ctr2.size()); \
return ctr2.begin() + (idx - ctr1.begin()); \
}
IBYI(const_iterator, const_iterator, const Container1, const Container2)
IBYI(iterator, iterator, Container1, Container2)
IBYI(const_iterator, iterator, const Container1, Container2)
IBYI(iterator, const_iterator, Container1, const Container2)
#else // DOXYGEN
#error "This declaration is for doxygen only; it is not compiled."
/// Converts a const_iterator in one container into a const_iterator in another container.
template <typename Container1, typename Container2>
inline typename Container2::iterator ibyi (typename Container1::iterator idx, Container1& ctr1, Container2& ctr2) {}
#endif // DOXYGEN
//----------------------------------------------------------------------
} // namespace ustl

View File

@ -0,0 +1,324 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "utypes.h"
#include "traits.h"
#if HAVE_CPP11
#include "uttraits.h"
#endif
namespace ustl {
enum float_denorm_style {
denorm_indeterminate = -1,
denorm_absent,
denorm_present
};
enum float_round_style {
round_indeterminate = -1,
round_toward_zero,
round_to_nearest,
round_toward_infinity,
round_toward_neg_infinity
};
namespace {
template <typename T>
struct __limits_digits { enum { value = sizeof(T)*8 };};
template <typename T>
struct __limits_digits10 { enum { value = sizeof(T)*8*643/2136+1 };};
}
/// \class numeric_limits ulimits.h ustl.h
/// \brief Defines numeric limits for a type.
///
template <typename T>
struct numeric_limits {
static inline constexpr T min (void) { return T(); } // Returns the minimum value for type T.
static inline constexpr T max (void) { return T(); } // Returns the minimum value for type T.
static inline constexpr T lowest (void) { return T(); }
static inline constexpr T epsilon (void) { return T(); }
static inline constexpr T round_error (void) { return T(); }
static inline constexpr T infinity (void) { return T(); }
static inline constexpr T quiet_NaN (void) { return T(); }
static inline constexpr T signaling_NaN (void) { return T(); }
static inline constexpr T denorm_min (void) { return T(); }
static constexpr const bool is_specialized = false;
static constexpr const bool is_signed = tm::TypeTraits<T>::isSigned; ///< True if the type is signed.
static constexpr const bool is_integer = tm::TypeTraits<T>::isIntegral; ///< True if stores an exact value.
static constexpr const bool is_exact = tm::TypeTraits<T>::isIntegral; ///< True if stores an exact value.
static constexpr const bool is_integral = tm::TypeTraits<T>::isFundamental; ///< True if fixed size and cast-copyable.
static constexpr const bool is_iec559 = false;
static constexpr const bool is_bounded = false;
static constexpr const bool is_modulo = false;
static constexpr const bool has_infinity = false;
static constexpr const bool has_quiet_NaN = false;
static constexpr const bool has_signaling_NaN = false;
static constexpr const bool has_denorm_loss = false;
static constexpr const bool traps = false;
static constexpr const bool tinyness_before = false;
static constexpr const int radix = 0;
static constexpr const int min_exponent = 0;
static constexpr const int min_exponent10 = 0;
static constexpr const int max_exponent = 0;
static constexpr const int max_exponent10 = 0;
static constexpr const float_denorm_style has_denorm = denorm_absent;
static constexpr const float_round_style round_style = round_toward_zero;
static constexpr const unsigned digits = __limits_digits<T>::value; ///< Number of bits in T
static constexpr const unsigned digits10 = 0;
static constexpr const unsigned max_digits10 = 0;
};
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template <typename T>
struct numeric_limits<T*> {
static inline constexpr T* min (void) { return nullptr; }
static inline constexpr T* max (void) { return reinterpret_cast<T*>(UINTPTR_MAX); }
static inline constexpr T* lowest (void) { return nullptr; }
static inline constexpr T* epsilon (void) { return nullptr; }
static inline constexpr T* round_error (void) { return nullptr; }
static inline constexpr T* infinity (void) { return nullptr; }
static inline constexpr T* quiet_NaN (void) { return nullptr; }
static inline constexpr T* signaling_NaN (void) { return nullptr; }
static inline constexpr T* denorm_min (void) { return nullptr; }
static constexpr const bool is_specialized = false;
static constexpr const bool is_signed = false;
static constexpr const bool is_integer = true;
static constexpr const bool is_exact = true;
static constexpr const bool is_integral = true;
static constexpr const bool is_iec559 = false;
static constexpr const bool is_bounded = true;
static constexpr const bool is_modulo = true;
static constexpr const bool has_infinity = false;
static constexpr const bool has_quiet_NaN = false;
static constexpr const bool has_signaling_NaN = false;
static constexpr const bool has_denorm_loss = false;
static constexpr const bool traps = false;
static constexpr const bool tinyness_before = false;
static constexpr const int radix = 2;
static constexpr const int min_exponent = 0;
static constexpr const int min_exponent10 = 0;
static constexpr const int max_exponent = 0;
static constexpr const int max_exponent10 = 0;
static constexpr const float_denorm_style has_denorm = denorm_absent;
static constexpr const float_round_style round_style = round_toward_zero;
static constexpr const unsigned digits = __limits_digits<T*>::value;
static constexpr const unsigned digits10 = __limits_digits10<T*>::value;
static constexpr const unsigned max_digits10 = 0;
};
/*
template <> struct numeric_limits<float> {
static inline constexpr float min (void) { return FLT_MIN; }
static inline constexpr float max (void) { return FLT_MAX; }
static inline constexpr float lowest (void) { return -FLT_MAX; }
static inline constexpr float epsilon (void) { return FLT_EPSILON; }
static inline constexpr float round_error (void) { return 0.5f; }
static inline constexpr float infinity (void) { return __builtin_huge_valf(); }
static inline constexpr float quiet_NaN (void) { return __builtin_nanf(""); }
static inline constexpr float signaling_NaN (void) { return __builtin_nansf(""); }
static inline constexpr float denorm_min (void) { return __FLT_DENORM_MIN__; }
static constexpr const bool is_specialized = true;
static constexpr const bool is_signed = true;
static constexpr const bool is_integer = false;
static constexpr const bool is_exact = false;
static constexpr const bool is_integral = true;
static constexpr const bool is_iec559 = true;
static constexpr const bool is_bounded = true;
static constexpr const bool is_modulo = false;
static constexpr const bool has_infinity = __FLT_HAS_INFINITY__;
static constexpr const bool has_quiet_NaN = __FLT_HAS_QUIET_NAN__;
static constexpr const bool has_signaling_NaN = __FLT_HAS_QUIET_NAN__;
static constexpr const bool has_denorm_loss = true;
static constexpr const bool traps = false;
static constexpr const bool tinyness_before = true;
static constexpr const int radix = FLT_RADIX;
static constexpr const int min_exponent = FLT_MIN_EXP;
static constexpr const int min_exponent10 = FLT_MIN_10_EXP;
static constexpr const int max_exponent = FLT_MAX_EXP;
static constexpr const int max_exponent10 = FLT_MAX_10_EXP;
static constexpr const float_denorm_style has_denorm = denorm_present;
static constexpr const float_round_style round_style = round_to_nearest;
static constexpr const unsigned digits = FLT_MANT_DIG;
static constexpr const unsigned digits10 = FLT_DIG;
static constexpr const unsigned max_digits10 = FLT_MANT_DIG;
};
template <> struct numeric_limits<double> {
static inline constexpr double min (void) { return DBL_MIN; }
static inline constexpr double max (void) { return DBL_MAX; }
static inline constexpr double lowest (void) { return -DBL_MAX; }
static inline constexpr double epsilon (void) { return DBL_EPSILON; }
static inline constexpr double round_error (void) { return 0.5; }
static inline constexpr double infinity (void) { return __builtin_huge_val(); }
static inline constexpr double quiet_NaN (void) { return __builtin_nan(""); }
static inline constexpr double signaling_NaN (void) { return __builtin_nans(""); }
static inline constexpr double denorm_min (void) { return __DBL_DENORM_MIN__; }
static constexpr const bool is_specialized = true;
static constexpr const bool is_signed = true;
static constexpr const bool is_integer = false;
static constexpr const bool is_exact = false;
static constexpr const bool is_integral = true;
static constexpr const bool is_iec559 = true;
static constexpr const bool is_bounded = true;
static constexpr const bool is_modulo = false;
static constexpr const bool has_infinity = __DBL_HAS_INFINITY__;
static constexpr const bool has_quiet_NaN = __DBL_HAS_QUIET_NAN__;
static constexpr const bool has_signaling_NaN = __DBL_HAS_QUIET_NAN__;
static constexpr const bool has_denorm_loss = true;
static constexpr const bool traps = false;
static constexpr const bool tinyness_before = true;
static constexpr const int radix = FLT_RADIX;
static constexpr const int min_exponent = DBL_MIN_EXP;
static constexpr const int min_exponent10 = DBL_MIN_10_EXP;
static constexpr const int max_exponent = DBL_MAX_EXP;
static constexpr const int max_exponent10 = DBL_MAX_10_EXP;
static constexpr const float_denorm_style has_denorm = denorm_present;
static constexpr const float_round_style round_style = round_to_nearest;
static constexpr const unsigned digits = DBL_MANT_DIG;
static constexpr const unsigned digits10 = DBL_DIG;
static constexpr const unsigned max_digits10 = DBL_MANT_DIG;
};
template <> struct numeric_limits<long double> {
static inline constexpr long double min (void) { return LDBL_MIN; }
static inline constexpr long double max (void) { return LDBL_MAX; }
static inline constexpr long double lowest (void) { return -LDBL_MAX; }
static inline constexpr long double epsilon (void) { return LDBL_EPSILON; }
static inline constexpr long double round_error (void) { return 0.5l; }
static inline constexpr long double infinity (void) { return __builtin_huge_vall(); }
static inline constexpr long double quiet_NaN (void) { return __builtin_nanl(""); }
static inline constexpr long double signaling_NaN (void) { return __builtin_nansl(""); }
static inline constexpr long double denorm_min (void) { return __LDBL_DENORM_MIN__; }
static constexpr const bool is_specialized = true;
static constexpr const bool is_signed = true;
static constexpr const bool is_integer = false;
static constexpr const bool is_exact = false;
static constexpr const bool is_integral = true;
static constexpr const bool is_iec559 = true;
static constexpr const bool is_bounded = true;
static constexpr const bool is_modulo = false;
static constexpr const bool has_infinity = __LDBL_HAS_INFINITY__;
static constexpr const bool has_quiet_NaN = __LDBL_HAS_QUIET_NAN__;
static constexpr const bool has_signaling_NaN = __LDBL_HAS_QUIET_NAN__;
static constexpr const bool has_denorm_loss = true;
static constexpr const bool traps = false;
static constexpr const bool tinyness_before = true;
static constexpr const int radix = FLT_RADIX;
static constexpr const int min_exponent = LDBL_MIN_EXP;
static constexpr const int min_exponent10 = LDBL_MIN_10_EXP;
static constexpr const int max_exponent = LDBL_MAX_EXP;
static constexpr const int max_exponent10 = LDBL_MAX_10_EXP;
static constexpr const float_denorm_style has_denorm = denorm_present;
static constexpr const float_round_style round_style = round_to_nearest;
static constexpr const unsigned digits = LDBL_MANT_DIG;
static constexpr const unsigned digits10 = LDBL_DIG;
static constexpr const unsigned max_digits10 = LDBL_MANT_DIG;
};
template <> struct numeric_limits<long double> {
static inline constexpr long double min (void) { return LDBL_MIN; }
static inline constexpr long double max (void) { return LDBL_MAX; }
static inline constexpr long double lowest (void) { return -LDBL_MAX; }
static inline constexpr long double epsilon (void) { return LDBL_EPSILON; }
static inline constexpr long double round_error (void) { return 0.5l; }
static inline constexpr long double infinity (void) { return __builtin_huge_vall(); }
static inline constexpr long double quiet_NaN (void) { return __builtin_nanl(""); }
static inline constexpr long double signaling_NaN (void) { return __builtin_nansl(""); }
static inline constexpr long double denorm_min (void) { return __LDBL_DENORM_MIN__; }
static constexpr const bool is_specialized = true;
static constexpr const bool is_signed = true;
static constexpr const bool is_integer = false;
static constexpr const bool is_exact = false;
static constexpr const bool is_integral = true;
static constexpr const bool is_iec559 = true;
static constexpr const bool is_bounded = true;
static constexpr const bool is_modulo = false;
static constexpr const bool has_infinity = __LDBL_HAS_INFINITY__;
static constexpr const bool has_quiet_NaN = __LDBL_HAS_QUIET_NAN__;
static constexpr const bool has_signaling_NaN = __LDBL_HAS_QUIET_NAN__;
static constexpr const bool has_denorm_loss = true;
static constexpr const bool traps = false;
static constexpr const bool tinyness_before = true;
static constexpr const int radix = FLT_RADIX;
static constexpr const int min_exponent = LDBL_MIN_EXP;
static constexpr const int min_exponent10 = LDBL_MIN_10_EXP;
static constexpr const int max_exponent = LDBL_MAX_EXP;
static constexpr const int max_exponent10 = LDBL_MAX_10_EXP;
static constexpr const float_denorm_style has_denorm = denorm_present;
static constexpr const float_round_style round_style = round_to_nearest;
static constexpr const unsigned digits = LDBL_MANT_DIG;
static constexpr const unsigned digits10 = LDBL_DIG;
static constexpr const unsigned max_digits10 = LDBL_MANT_DIG;
};*/
#define _NUMERIC_LIMITS(type, minVal, maxVal, bSigned, bInteger, bIntegral) \
template <> struct numeric_limits<type> { \
static inline constexpr type min (void) { return minVal; } \
static inline constexpr type max (void) { return maxVal; } \
static inline constexpr type lowest (void) { return minVal; } \
static inline constexpr type epsilon (void) { return 0; } \
static inline constexpr type round_error (void) { return 0; } \
static inline constexpr type infinity (void) { return 0; } \
static inline constexpr type quiet_NaN (void) { return 0; } \
static inline constexpr type signaling_NaN (void) { return 0; } \
static inline constexpr type denorm_min (void) { return 0; } \
static constexpr const bool is_specialized = true; \
static constexpr const bool is_signed = bSigned; \
static constexpr const bool is_integer = bInteger; \
static constexpr const bool is_exact = bInteger; \
static constexpr const bool is_integral = bIntegral; \
static constexpr const bool is_iec559 = false; \
static constexpr const bool is_bounded = true; \
static constexpr const bool is_modulo = bIntegral; \
static constexpr const bool has_infinity = false; \
static constexpr const bool has_quiet_NaN = false; \
static constexpr const bool has_signaling_NaN = false; \
static constexpr const bool has_denorm_loss = false; \
static constexpr const bool traps = false; \
static constexpr const bool tinyness_before = false; \
static constexpr const int radix = 2; \
static constexpr const int min_exponent = 0; \
static constexpr const int min_exponent10 = 0; \
static constexpr const int max_exponent = 0; \
static constexpr const int max_exponent10 = 0; \
static constexpr const float_denorm_style has_denorm = denorm_absent; \
static constexpr const float_round_style round_style = round_toward_zero; \
static constexpr const unsigned digits = __limits_digits<type>::value; \
static constexpr const unsigned digits10 = __limits_digits10<type>::value; \
static constexpr const unsigned max_digits10 = 0; \
}
//--------------------------------------------------------------------------------------
// type min max signed integer integral
//--------------------------------------------------------------------------------------
_NUMERIC_LIMITS (bool, false, true, false, false, true);
_NUMERIC_LIMITS (char, CHAR_MIN, CHAR_MAX, true, true, true);
_NUMERIC_LIMITS (int, INT_MIN, INT_MAX, true, true, true);
_NUMERIC_LIMITS (short, SHRT_MIN, SHRT_MAX, true, true, true);
_NUMERIC_LIMITS (long, LONG_MIN, LONG_MAX, true, true, true);
#if HAVE_THREE_CHAR_TYPES
_NUMERIC_LIMITS (signed char, SCHAR_MIN, SCHAR_MAX, true, true, true);
#endif
_NUMERIC_LIMITS (unsigned char, 0, UCHAR_MAX, false, true, true);
_NUMERIC_LIMITS (unsigned int, 0, UINT_MAX, false, true, true);
_NUMERIC_LIMITS (unsigned short,0, USHRT_MAX, false, true, true);
_NUMERIC_LIMITS (unsigned long, 0, ULONG_MAX, false, true, true);
_NUMERIC_LIMITS (wchar_t, 0, WCHAR_MAX, false, true, true);
#if HAVE_LONG_LONG
_NUMERIC_LIMITS (long long, LLONG_MIN, LLONG_MAX, true, true, true);
_NUMERIC_LIMITS (unsigned long long, 0, ULLONG_MAX, false, true, true);
#endif
//--------------------------------------------------------------------------------------
#endif // DOXYGEN_SHOULD_SKIP_THIS
/// Macro for defining numeric_limits specializations
#define NUMERIC_LIMITS(type, minVal, maxVal, bSigned, bInteger, bIntegral) \
namespace ustl { _NUMERIC_LIMITS (type, minVal, maxVal, bSigned, bInteger, bIntegral); }
} // namespace ustl

View File

@ -0,0 +1,85 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "uvector.h"
#include "uctralgo.h"
namespace ustl {
/// \class list ulist.h ustl.h
/// \ingroup Sequences
///
/// \brief Linked list, defined as an alias to vector.
///
template <typename T>
class list : public vector<T> {
public:
typedef typename vector<T>::size_type size_type;
typedef typename vector<T>::iterator iterator;
typedef typename vector<T>::const_iterator const_iterator;
typedef typename vector<T>::reference reference;
typedef typename vector<T>::const_reference const_reference;
public:
inline list (void) : vector<T> () {}
inline explicit list (size_type n) : vector<T> (n) {}
inline list (size_type n, const T& v) : vector<T> (n, v) {}
inline list (const list<T>& v) : vector<T> (v) {}
inline list (const_iterator i1, const_iterator i2) : vector<T> (i1, i2) {}
inline size_type size (void) const { return vector<T>::size(); }
inline iterator begin (void) { return vector<T>::begin(); }
inline const_iterator begin (void) const { return vector<T>::begin(); }
inline iterator end (void) { return vector<T>::end(); }
inline const_iterator end (void) const { return vector<T>::end(); }
inline void push_front (const T& v) { this->insert (begin(), v); }
inline void pop_front (void) { this->erase (begin()); }
inline const_reference front (void) const { return *begin(); }
inline reference front (void) { return *begin(); }
inline void remove (const T& v) { ::ustl::remove (*this, v); }
template <typename Predicate>
inline void remove_if (Predicate p) { ::ustl::remove_if (*this, p); }
inline void reverse (void) { ::ustl::reverse (*this); }
inline void unique (void) { ::ustl::unique (*this); }
inline void sort (void) { ::ustl::sort (*this); }
void merge (list<T>& l);
void splice (iterator ip, list<T>& l, iterator first = nullptr, iterator last = nullptr);
#if HAVE_CPP11
inline list (list&& v) : vector<T> (move(v)) {}
inline list (std::initializer_list<T> v) : vector<T>(v) {}
inline list& operator= (list&& v) { vector<T>::operator= (move(v)); return *this; }
template <typename... Args>
inline void emplace_front (Args&&... args) { vector<T>::emplace (begin(), forward<Args>(args)...); }
inline void push_front (T&& v) { emplace_front (move(v)); }
#endif
};
/// Merges the contents with \p l. Assumes both lists are sorted.
template <typename T>
void list<T>::merge (list& l)
{
this->insert_space (begin(), l.size());
::ustl::merge (this->iat(l.size()), end(), l.begin(), l.end(), begin());
}
/// Moves the range [first, last) from \p l to this list at \p ip.
template <typename T>
void list<T>::splice (iterator ip, list<T>& l, iterator first, iterator last)
{
if (!first)
first = l.begin();
if (!last)
last = l.end();
this->insert (ip, first, last);
l.erase (first, last);
}
#if HAVE_CPP11
template <typename T> using deque = list<T>;
#else
#define deque list ///< list has all the functionality provided by deque
#endif
} // namespace ustl

View File

@ -0,0 +1,168 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "uvector.h"
#include "ufunction.h"
namespace ustl {
template <typename Pair, typename Comp>
struct pair_compare_first : public binary_function<Pair,Pair,bool> {
inline bool operator()(const Pair& a, const Pair& b) { return Comp()(a.first,b.first); }
};
template <typename K, typename V, typename Comp>
struct pair_compare_first_key : public binary_function<pair<K,V>,K,bool> {
inline bool operator()(const pair<K,V>& a, const K& b) { return Comp()(a.first,b); }
inline bool operator()(const K& a, const pair<K,V>& b) { return Comp()(a,b.first); }
};
/// \class map umap.h ustl.h
/// \ingroup AssociativeContainers
///
/// \brief A sorted associative container of pair<K,V>
///
template <typename K, typename V, typename Comp = less<K> >
class map : public vector<pair<K,V> > {
public:
typedef K key_type;
typedef V data_type;
typedef const K& const_key_ref;
typedef const V& const_data_ref;
typedef const map<K,V,Comp>& rcself_t;
typedef vector<pair<K,V> > base_class;
typedef typename base_class::value_type value_type;
typedef typename base_class::size_type size_type;
typedef typename base_class::pointer pointer;
typedef typename base_class::const_pointer const_pointer;
typedef typename base_class::reference reference;
typedef typename base_class::const_reference const_reference;
typedef typename base_class::const_iterator const_iterator;
typedef typename base_class::iterator iterator;
typedef typename base_class::reverse_iterator reverse_iterator;
typedef typename base_class::const_reverse_iterator const_reverse_iterator;
typedef pair<const_iterator,const_iterator> const_range_t;
typedef pair<iterator,iterator> range_t;
typedef pair<iterator,bool> insertrv_t;
typedef Comp key_compare;
typedef pair_compare_first<value_type,Comp> value_compare;
typedef pair_compare_first_key<K,V,Comp> value_key_compare;
public:
inline map (void) : base_class() {}
explicit inline map (size_type n) : base_class (n) {}
inline map (rcself_t v) : base_class (v) {}
inline map (const_iterator i1, const_iterator i2) : base_class() { insert (i1, i2); }
inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return *this; }
inline const_data_ref at (const_key_ref k) const { assert (find(k) != end()); return find(k)->second; }
inline data_type& at (const_key_ref k) { assert (find(k) != end()); return find(k)->second; }
inline const_data_ref operator[] (const_key_ref i) const { return at(i); }
data_type& operator[] (const_key_ref i);
inline key_compare key_comp (void) const { return key_compare(); }
inline value_compare value_comp (void) const { return value_compare(); }
inline size_type size (void) const { return base_class::size(); }
inline iterator begin (void) { return base_class::begin(); }
inline const_iterator begin (void) const { return base_class::begin(); }
inline iterator end (void) { return base_class::end(); }
inline const_iterator end (void) const { return base_class::end(); }
inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); }
inline void push_back (const_reference v) { insert (v); }
inline const_iterator find (const_key_ref k) const;
inline iterator find (const_key_ref k) { return const_cast<iterator> (const_cast<rcself_t>(*this).find (k)); }
inline const_iterator find_data (const_data_ref v, const_iterator first = nullptr, const_iterator last = nullptr) const;
inline iterator find_data (const_data_ref v, iterator first = nullptr, iterator last = nullptr) { return const_cast<iterator> (find_data (v, const_cast<const_iterator>(first), const_cast<const_iterator>(last))); }
const_iterator lower_bound (const_key_ref k) const { return ::ustl::lower_bound (begin(), end(), k, value_key_compare()); }
inline iterator lower_bound (const_key_ref k) { return const_cast<iterator>(const_cast<rcself_t>(*this).lower_bound (k)); }
const_iterator upper_bound (const_key_ref k) const { return ::ustl::upper_bound (begin(), end(), k, value_key_compare()); }
inline iterator upper_bound (const_key_ref k) { return const_cast<iterator>(const_cast<rcself_t>(*this).upper_bound (k)); }
const_range_t equal_range (const_key_ref k) const { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); }
inline range_t equal_range (const_key_ref k) { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); }
inline size_type count (const_key_ref v) const { const_range_t r = equal_range(v); return distance(r.first,r.second); }
insertrv_t insert (const_reference v);
inline iterator insert (const_iterator, const_reference v) { return insert(v).first; }
void insert (const_iterator i1, const_iterator i2) { for (; i1 != i2; ++i1) insert (*i1); }
inline void erase (const_key_ref k);
inline iterator erase (iterator ep) { return base_class::erase (ep); }
inline iterator erase (iterator ep1, iterator ep2) { return base_class::erase (ep1, ep2); }
inline void clear (void) { base_class::clear(); }
inline void swap (map& v) { base_class::swap (v); }
#if HAVE_CPP11
using initlist_t = std::initializer_list<value_type>;
inline map (map&& v) : base_class (move(v)) {}
inline map (initlist_t v) : base_class() { insert (v.begin(), v.end()); }
inline map& operator= (map&& v) { base_class::operator= (move(v)); return *this; }
insertrv_t insert (value_type&& v);
inline iterator insert (const_iterator, value_type&& v) { return insert(move(v)).first; }
inline void insert (initlist_t v) { insert (v.begin(), v.end()); }
template <typename... Args>
inline insertrv_t emplace (Args&&... args) { return insert (value_type(forward<Args>(args)...)); }
template <typename... Args>
inline iterator emplace_hint (const_iterator h, Args&&... args) { return insert (h, value_type(forward<Args>(args)...)); }
template <typename... Args>
inline insertrv_t emplace_back (Args&&... args) { return insert (value_type(forward<Args>(args)...)); }
#endif
};
/// Returns the pair<K,V> where K = \p k.
template <typename K, typename V, typename Comp>
inline typename map<K,V,Comp>::const_iterator map<K,V,Comp>::find (const_key_ref k) const
{
const_iterator i = lower_bound (k);
return (i < end() && Comp()(k,i->first)) ? end() : i;
}
/// Returns the pair<K,V> where V = \p v, occuring in range [first,last).
template <typename K, typename V, typename Comp>
inline typename map<K,V,Comp>::const_iterator map<K,V,Comp>::find_data (const_data_ref v, const_iterator first, const_iterator last) const
{
if (!first) first = begin();
if (!last) last = end();
for (; first != last && first->second != v; ++first) ;
return first;
}
/// Returns data associated with key \p k.
template <typename K, typename V, typename Comp>
typename map<K,V,Comp>::data_type& map<K,V,Comp>::operator[] (const_key_ref k)
{
iterator ip = lower_bound (k);
if (ip == end() || Comp()(k,ip->first))
ip = base_class::insert (ip, make_pair (k, V()));
return ip->second;
}
/// Inserts the pair into the container.
template <typename K, typename V, typename Comp>
typename map<K,V,Comp>::insertrv_t map<K,V,Comp>::insert (const_reference v)
{
iterator ip = lower_bound (v.first);
bool bInserted = ip == end() || Comp()(v.first, ip->first);
if (bInserted)
ip = base_class::insert (ip, v);
return make_pair (ip, bInserted);
}
#if HAVE_CPP11
/// Inserts the pair into the container.
template <typename K, typename V, typename Comp>
typename map<K,V,Comp>::insertrv_t map<K,V,Comp>::insert (value_type&& v)
{
iterator ip = lower_bound (v.first);
bool bInserted = ip == end() || Comp()(v.first, ip->first);
if (bInserted)
ip = base_class::insert (ip, move(v));
return make_pair (ip, bInserted);
}
#endif
/// Erases the element with key value \p k.
template <typename K, typename V, typename Comp>
inline void map<K,V,Comp>::erase (const_key_ref k)
{
iterator ip = find (k);
if (ip != end())
erase (ip);
}
} // namespace ustl

View File

@ -0,0 +1,546 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "unew.h"
#include "uatomic.h"
#include "uiterator.h"
#include "ulimits.h"
#include "upair.h"
namespace ustl {
//{{{ auto_ptr -------------------------------------------------------
/// \class auto_ptr umemory.h ustl.h
/// \ingroup MemoryManagement
///
/// \brief A smart pointer.
///
/// Calls delete in the destructor; assignment transfers ownership.
/// This class does not work with void pointers due to the absence
/// of the required dereference operator. auto_ptr is deprecated in
/// c++11; use unique_ptr instead.
///
template <typename T>
class auto_ptr {
public:
typedef T value_type;
typedef T* pointer;
typedef T& reference;
public:
/// Takes ownership of \p p.
inline explicit auto_ptr (pointer p = nullptr) : _p (p) {}
/// Takes ownership of pointer in \p p. \p p relinquishes ownership.
inline auto_ptr (auto_ptr<T>& p) : _p (p.release()) {}
/// Deletes the owned pointer.
inline ~auto_ptr (void) { delete _p; }
/// Returns the pointer without relinquishing ownership.
inline pointer get (void) const { return _p; }
/// Returns the pointer and gives up ownership.
inline pointer release (void) { pointer rv (_p); _p = nullptr; return rv; }
/// Deletes the pointer and sets it equal to \p p.
inline void reset (pointer p) { if (p != _p) { delete _p; _p = p; } }
/// Takes ownership of \p p.
inline auto_ptr<T>& operator= (pointer p) { reset (p); return *this; }
/// Takes ownership of pointer in \p p. \p p relinquishes ownership.
inline auto_ptr<T>& operator= (auto_ptr<T>& p) { reset (p.release()); return *this; }
inline reference operator* (void) const { return *_p; }
inline pointer operator-> (void) const { return _p; }
inline bool operator== (const pointer p) const { return _p == p; }
inline bool operator== (const auto_ptr<T>& p) const { return _p == p._p; }
inline bool operator< (const auto_ptr<T>& p) const { return p._p < _p; }
private:
pointer _p;
};
//}}}-------------------------------------------------------------------
//{{{ unique_ptr
#if HAVE_CPP11
/// \class unique_ptr memory.h stl.h
/// \ingroup MemoryManagement
/// \brief A smart pointer.
/// Calls delete in the destructor; assignment transfers ownership.
/// This class does not work with void pointers due to the absence
/// of the required dereference operator.
template <typename T>
class unique_ptr {
public:
using element_type = T;
using pointer = element_type*;
using reference = element_type&;
public:
inline constexpr unique_ptr (void) : _p (nullptr) {}
inline constexpr explicit unique_ptr (pointer p) : _p (p) {}
inline unique_ptr (unique_ptr&& p) : _p (p.release()) {}
unique_ptr (const unique_ptr&) = delete;
inline ~unique_ptr (void) { delete _p; }
inline constexpr pointer get (void) const { return _p; }
inline pointer release (void) { auto rv (_p); _p = nullptr; return rv; }
inline void reset (pointer p = nullptr) { assert (p != _p || !p); auto ov (_p); _p = p; delete ov; }
inline void swap (unique_ptr& v) { ::ustl::swap (_p, v._p); }
inline constexpr explicit operator bool (void) const { return _p != nullptr; }
inline unique_ptr& operator= (pointer p) { reset (p); return *this; }
inline unique_ptr& operator= (unique_ptr&& p) { reset (p.release()); return *this; }
unique_ptr& operator=(const unique_ptr&) = delete;
inline constexpr reference operator* (void) const { return *get(); }
inline constexpr pointer operator-> (void) const { return get(); }
inline constexpr reference operator[] (size_t i) const { return get()[i]; }
inline constexpr bool operator== (const pointer p) const { return _p == p; }
inline constexpr bool operator== (const unique_ptr& p) const { return _p == p._p; }
inline constexpr bool operator< (const unique_ptr& p) const { return _p < p._p; }
private:
pointer _p;
};
// array version
template<typename T>
class unique_ptr<T[]> {
public:
using element_type = T;
using pointer = element_type*;
using reference = element_type&;
public:
inline constexpr unique_ptr (void) : _p (nullptr) {}
inline constexpr explicit unique_ptr (pointer p) : _p (p) {}
inline unique_ptr (unique_ptr&& p) : _p (p.release()) {}
unique_ptr(const unique_ptr&) = delete;
inline ~unique_ptr (void) { delete [] _p; }
inline constexpr pointer get (void) const { return _p; }
inline pointer release (void) { auto rv (_p); _p = nullptr; return rv; }
inline void reset (pointer p) { assert (p != _p); auto ov (_p); _p = p; delete [] ov; }
inline void swap (unique_ptr& v) { ::ustl::swap (_p, v._p); }
inline constexpr explicit operator bool (void) const { return _p != nullptr; }
inline unique_ptr& operator= (pointer p) { reset (p); return *this; }
inline unique_ptr& operator= (unique_ptr&& p) { reset (p.release()); return *this; }
unique_ptr& operator=(const unique_ptr&) = delete;
inline constexpr reference operator* (void) const { return *_p; }
inline constexpr pointer operator-> (void) const { return _p; }
inline constexpr reference operator[] (size_t i) const { return _p[i]; }
inline constexpr bool operator== (const pointer p) const { return _p == p; }
inline constexpr bool operator== (const unique_ptr& p) const { return _p == p._p; }
inline constexpr bool operator< (const unique_ptr& p) const { return _p < p._p; }
private:
pointer _p;
};
#if HAVE_CPP14
template <typename T> struct __make_unique { using __single_object = unique_ptr<T>; };
template <typename T> struct __make_unique<T[]> { using __array = unique_ptr<T[]>; };
template <typename T, size_t N> struct __make_unique<T[N]> { struct __invalid_type {}; };
template <typename T, typename... Args>
inline typename __make_unique<T>::__single_object
make_unique (Args&&... args) { return unique_ptr<T> (new T (forward<Args>(args)...)); }
template <typename T>
inline typename __make_unique<T>::__array
make_unique (size_t n) { return unique_ptr<T> (new remove_extent_t<T>[n]()); }
template <typename T, typename... Args>
inline typename __make_unique<T>::__invalid_type
make_unique (Args&&...) = delete;
#endif // HAVE_CPP14
#endif // HAVE_CPP11
//}}}-------------------------------------------------------------------
//{{{ shared_ptr
#if HAVE_CPP11
/// \class shared_ptr memory.h stl.h
/// \ingroup MemoryManagement
/// \brief A smart pointer.
/// Calls delete in the destructor; assignment shares ownership.
template <typename T>
class shared_ptr {
public:
using element_type = T;
using pointer = element_type*;
using reference = element_type&;
private:
struct container {
pointer p;
atomic<size_t> refs;
inline constexpr explicit container (pointer np) : p(np),refs(1) {}
inline ~container (void) noexcept { assert (!refs); delete p; }
};
public:
inline constexpr shared_ptr (void) : _p (nullptr) {}
inline explicit shared_ptr (pointer p) : _p (new container (p)) {}
inline shared_ptr (shared_ptr&& p) : _p (p._p) { p._p = nullptr; }
inline shared_ptr (const shared_ptr& p): _p (p._p) { if (_p) ++_p->refs; }
inline ~shared_ptr (void) { reset(); }
inline constexpr size_t use_count (void) const { return _p ? _p->refs.load() : 0; }
inline constexpr bool unique (void) const { return use_count() == 1; }
inline constexpr pointer get (void) const { return _p ? _p->p : nullptr; }
void reset (pointer p = nullptr) {
assert (p != get() || !p);
auto ov = _p;
_p = p ? new container(p) : nullptr;
if (ov && !--ov->refs)
delete ov;
}
inline void swap (shared_ptr& v) { ::ustl::swap (_p, v._p); }
inline constexpr explicit operator bool (void) const { return get(); }
inline shared_ptr& operator= (pointer p) { reset (p); return *this; }
inline shared_ptr& operator= (shared_ptr&& p) { swap (p); return *this; }
inline shared_ptr& operator= (const shared_ptr& p) { reset(); _p = p._p; if (_p) ++_p->refs; return *this; }
inline constexpr reference operator* (void) const { return *get(); }
inline constexpr pointer operator-> (void) const { return get(); }
inline constexpr reference operator[] (size_t i) const { return get()[i]; }
inline constexpr bool operator== (const pointer p) const { return get() == p; }
inline constexpr bool operator== (const shared_ptr& p) const { return get() == p.get(); }
inline constexpr bool operator< (const shared_ptr& p) const { return get() < p.get(); }
private:
container* _p;
};
#if HAVE_CPP14
template <typename T, typename... Args>
inline auto make_shared (Args&&... args)
{ return shared_ptr<T> (new T (forward<Args>(args)...)); }
#endif // HAVE_CPP14
//}}}-------------------------------------------------------------------
//{{{ scope_exit
template <typename F>
class scope_exit {
public:
inline explicit scope_exit (F&& f) noexcept : _f(move(f)),_enabled(true) {}
inline scope_exit (scope_exit&& f) noexcept : _f(move(f._f)),_enabled(f._enabled) { f.release(); }
inline void release (void) noexcept { _enabled = false; }
inline ~scope_exit (void) noexcept (noexcept (declval<F>())) { if (_enabled) _f(); }
scope_exit (const scope_exit&) = delete;
scope_exit& operator= (const scope_exit&) = delete;
scope_exit& operator= (scope_exit&&) = delete;
private:
F _f;
bool _enabled;
};
#if HAVE_CPP14
template <typename F>
auto make_scope_exit (F&& f) noexcept
{ return scope_exit<remove_reference_t<F>>(forward<F>(f)); }
#endif // HAVE_CPP14
//}}}-------------------------------------------------------------------
//{{{ unique_resource
template <typename R, typename D>
class unique_resource {
public:
inline explicit unique_resource (R&& resource, D&& deleter, bool enabled = true) noexcept
: _resource(move(resource)), _deleter(move(deleter)),_enabled(enabled) {}
inline unique_resource (unique_resource&& r) noexcept
: _resource(move(r._resource)),_deleter(move(r._deleter)),_enabled(r._enabled) { r.release(); }
unique_resource (const unique_resource&) = delete;
inline ~unique_resource() noexcept(noexcept(declval<unique_resource<R,D>>().reset()))
{ reset(); }
inline const D& get_deleter (void) const noexcept { return _deleter; }
inline R const& get (void) const noexcept { return _resource; }
inline R const& release (void) noexcept { _enabled = false; return get(); }
inline void reset (void) noexcept (noexcept(declval<D>())) {
if (_enabled) {
_enabled = false;
get_deleter()(_resource);
}
}
inline void reset (R&& r) noexcept (noexcept(reset())) {
reset();
_resource = move(r);
_enabled = true;
}
unique_resource& operator= (const unique_resource&) = delete;
unique_resource& operator= (unique_resource &&r) noexcept(noexcept(reset())) {
reset();
_deleter = move(r._deleter);
_resource = move(r._resource);
_enabled = r._enabled;
r.release();
return *this;
}
inline operator R const& (void) const noexcept { return get(); }
inline R operator-> (void) const noexcept { return _resource; }
inline add_lvalue_reference_t<remove_pointer_t<R>>
operator* (void) const { return *_resource; }
private:
R _resource;
D _deleter;
bool _enabled;
};
#if HAVE_CPP14
template <typename R,typename D>
auto make_unique_resource (R&& r, D&& d) noexcept
{ return unique_resource<R,remove_reference_t<D>>(move(r), forward<remove_reference_t<D>>(d), true); }
template <typename R,typename D>
auto make_unique_resource_checked (R r, R invalid, D d) noexcept
{
bool shouldrun = !(r == invalid);
return unique_resource<R,D>(move(r), move(d), shouldrun);
}
#endif // HAVE_CPP14
#endif // HAVE_CPP11
//}}}-------------------------------------------------------------------
//{{{ construct and destroy
/// Calls the placement new on \p p.
/// \ingroup RawStorageAlgorithms
///
template <typename T>
inline void construct_at (T* p)
{ new (p) T; }
/// Calls the placement new on \p p.
/// \ingroup RawStorageAlgorithms
///
template <typename T>
inline void construct_at (T* p, const T& value)
{ new (p) T (value); }
#if HAVE_CPP11
/// Calls the move placement new on \p p.
/// \ingroup RawStorageAlgorithms
///
template <typename T>
inline void construct_at (T* p, T&& value)
{ new (p) T (move<T>(value)); }
#endif
template <typename T>
inline void construct (T* p)
{ construct_at(p); }
/// Calls the placement new on \p p.
/// \ingroup RawStorageAlgorithms
///
template <typename ForwardIterator>
inline void uninitialized_default_construct (ForwardIterator first, ForwardIterator last)
{
typedef typename iterator_traits<ForwardIterator>::value_type value_type;
#if HAVE_CPP11
if (is_pod<value_type>::value)
#else
if (numeric_limits<value_type>::is_integral)
#endif
memset (reinterpret_cast<void*>(first), 0, max(distance(first,last),0)*sizeof(value_type));
else
for (--last; intptr_t(first) <= intptr_t(last); ++first)
construct_at (&*first);
}
template <typename ForwardIterator>
inline void uninitialized_default_construct_n (ForwardIterator first, size_t n)
{ uninitialized_default_construct (first, first+n); }
template <typename ForwardIterator>
inline void construct (ForwardIterator first, ForwardIterator last)
{ uninitialized_default_construct (first, last); }
/// Calls the placement new on \p [first,last) with iterator_traits::value_type()
template <typename ForwardIterator>
inline void uninitialized_value_construct (ForwardIterator first, ForwardIterator last)
{
typedef typename iterator_traits<ForwardIterator>::value_type value_type;
for (--last; intptr_t(first) <= intptr_t(last); ++first)
construct_at (&*first, value_type());
}
template <typename ForwardIterator>
inline void uninitialized_value_construct_n (ForwardIterator first, size_t n)
{ uninitialized_value_construct (first, first+n); }
/// Calls the destructor of \p p without calling delete.
/// \ingroup RawStorageAlgorithms
///
template <typename T>
inline void destroy_at (T* p) noexcept
{ p->~T(); }
template <typename T>
inline void destroy (T* p) noexcept
{ destroy_at(p); }
// Helper templates to not instantiate anything for integral types.
namespace {
template <typename T>
void dtors (T first, T last) noexcept
{ for (--last; intptr_t(first) <= intptr_t(last); ++first) destroy_at (&*first); }
template <typename T, bool bIntegral>
struct Sdtorsr {
inline void operator()(T first, T last) noexcept { dtors (first, last); }
};
template <typename T>
struct Sdtorsr<T,true> {
inline void operator()(T, T) noexcept {}
};
} // namespace
/// Calls the destructor on elements in range [first, last) without calling delete.
/// \ingroup RawStorageAlgorithms
///
template <typename ForwardIterator>
inline void destroy (ForwardIterator first, ForwardIterator last) noexcept
{
typedef typename iterator_traits<ForwardIterator>::value_type value_type;
#if HAVE_CPP11
Sdtorsr<ForwardIterator,is_pod<value_type>::value>()(first, last);
#else
Sdtorsr<ForwardIterator,numeric_limits<value_type>::is_integral>()(first, last);
#endif
}
template <typename ForwardIterator>
inline void destroy_n (ForwardIterator first, size_t n) noexcept
{ destroy (first, first+n); }
//}}}-------------------------------------------------------------------
//{{{ Raw storage algorithms
//}}}-------------------------------------------------------------------
//{{{ Raw storage algorithms
template <typename T> inline T* cast_to_type (void* p, const T*) { return reinterpret_cast<T*>(p); }
/// \brief Creates a temporary buffer pair from \p p and \p n
/// This is intended to be used with alloca to create temporary buffers.
/// The size in the returned pair is set to 0 if the allocation is unsuccessful.
/// \ingroup RawStorageAlgorithms
///
template <typename T>
inline pair<T*, ptrdiff_t> make_temporary_buffer (void* p, size_t n, const T* ptype)
{
return make_pair (cast_to_type(p,ptype), ptrdiff_t(p ? n : 0));
}
#if HAVE_ALLOCA_H
/// \brief Allocates a temporary buffer, if possible.
/// \ingroup RawStorageAlgorithms
#define get_temporary_buffer(size, ptype) make_temporary_buffer (alloca(size_of_elements(size, ptype)), size, ptype)
#define return_temporary_buffer(p)
#else
#define get_temporary_buffer(size, ptype) make_temporary_buffer (malloc(size_of_elements(size, ptype)), size, ptype)
#define return_temporary_buffer(p) if (p) free (p), p = nullptr
#endif
/// Copies [first, last) into result by calling copy constructors in result.
/// \ingroup RawStorageAlgorithms
///
template <typename InputIterator, typename ForwardIterator>
ForwardIterator uninitialized_copy (InputIterator first, InputIterator last, ForwardIterator result)
{
for (; first < last; ++result, ++first)
construct_at (&*result, *first);
return result;
}
/// Copies [first, first + n) into result by calling copy constructors in result.
/// \ingroup RawStorageAlgorithms
///
template <typename InputIterator, typename ForwardIterator>
ForwardIterator uninitialized_copy_n (InputIterator first, size_t n, ForwardIterator result)
{
for (++n; --n; ++result, ++first)
construct_at (&*result, *first);
return result;
}
/// Calls construct on all elements in [first, last) with value \p v.
/// \ingroup RawStorageAlgorithms
///
template <typename ForwardIterator, typename T>
void uninitialized_fill (ForwardIterator first, ForwardIterator last, const T& v)
{
for (; first < last; ++first)
construct_at (&*first, v);
}
/// Calls construct on all elements in [first, first + n) with value \p v.
/// \ingroup RawStorageAlgorithms
///
template <typename ForwardIterator, typename T>
ForwardIterator uninitialized_fill_n (ForwardIterator first, size_t n, const T& v)
{
for (++n; --n; ++first)
construct_at (&*first, v);
return first;
}
#if HAVE_CPP11
/// Moves [first, last) into result by calling move constructors in result.
/// \ingroup RawStorageAlgorithms
///
template <typename InputIterator, typename ForwardIterator>
ForwardIterator uninitialized_move (InputIterator first, InputIterator last, ForwardIterator result)
{
for (; first < last; ++result, ++first)
construct_at (&*result, move(*first));
return result;
}
/// Moves [first, first + n) into result by calling move constructors in result.
/// \ingroup RawStorageAlgorithms
///
template <typename InputIterator, typename ForwardIterator>
ForwardIterator uninitialized_move_n (InputIterator first, size_t n, ForwardIterator result)
{
for (++n; --n; ++result, ++first)
construct_at (&*result, move(*first));
return result;
}
#endif // HAVE_CPP11
} // namespace ustl
//}}}-------------------------------------------------------------------
//{{{ initializer_list
#if HAVE_CPP11 && WITHOUT_LIBSTDCPP
namespace std { // Internal stuff must be in std::
/// Internal class for compiler support of C++11 initializer lists
template <typename T>
class initializer_list {
public:
typedef T value_type;
typedef size_t size_type;
typedef const T& const_reference;
typedef const_reference reference;
typedef const T* const_iterator;
typedef const_iterator iterator;
private:
/// This object is only constructed by the compiler when the {1,2,3}
/// syntax is used, so the constructor must be private
inline constexpr initializer_list (const_iterator p, size_type sz) noexcept : _data(p), _size(sz) {}
public:
inline constexpr initializer_list (void)noexcept : _data(nullptr), _size(0) {}
inline constexpr size_type size (void) const noexcept { return _size; }
inline constexpr const_iterator begin() const noexcept { return _data; }
inline constexpr const_iterator end() const noexcept { return begin()+size(); }
private:
iterator _data;
size_type _size;
};
template <typename T>
inline constexpr const T* begin (initializer_list<T> il) noexcept { return il.begin(); }
template <typename T>
inline constexpr const T* end (initializer_list<T> il) noexcept { return il.end(); }
} // namespace std
#endif // HAVE_CPP11
//}}}-------------------------------------------------------------------

View File

@ -0,0 +1,96 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "umap.h"
namespace ustl {
/// \class multimap umultimap.h ustl.h
/// \ingroup AssociativeContainers
///
/// \brief A sorted associative container that may container multiple entries for each key.
///
template <typename K, typename V, typename Comp = less<K> >
class multimap : public vector<pair<K,V> > {
public:
typedef K key_type;
typedef V data_type;
typedef const K& const_key_ref;
typedef const V& const_data_ref;
typedef const multimap<K,V,Comp>& rcself_t;
typedef vector<pair<K,V> > base_class;
typedef typename base_class::value_type value_type;
typedef typename base_class::size_type size_type;
typedef typename base_class::pointer pointer;
typedef typename base_class::const_pointer const_pointer;
typedef typename base_class::reference reference;
typedef typename base_class::const_reference const_reference;
typedef typename base_class::const_iterator const_iterator;
typedef typename base_class::iterator iterator;
typedef typename base_class::reverse_iterator reverse_iterator;
typedef typename base_class::const_reverse_iterator const_reverse_iterator;
typedef pair<const_iterator,const_iterator> const_range_t;
typedef pair<iterator,iterator> range_t;
typedef Comp key_compare;
typedef pair_compare_first<value_type,Comp> value_compare;
typedef pair_compare_first_key<K,V,Comp> value_key_compare;
public:
inline multimap (void) : base_class() {}
explicit inline multimap (size_type n) : base_class (n) {}
inline multimap (rcself_t v) : base_class (v) {}
inline multimap (const_iterator i1, const_iterator i2) : base_class() { insert (i1, i2); }
inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return *this; }
inline key_compare key_comp (void) const { return key_compare(); }
inline value_compare value_comp (void) const { return value_compare(); }
inline size_type size (void) const { return base_class::size(); }
inline iterator begin (void) { return base_class::begin(); }
inline const_iterator begin (void) const { return base_class::begin(); }
inline iterator end (void) { return base_class::end(); }
inline const_iterator end (void) const { return base_class::end(); }
inline const_iterator find (const_key_ref k) const;
inline iterator find (const_key_ref k) { return const_cast<iterator> (const_cast<rcself_t>(*this).find (k)); }
const_iterator lower_bound (const_key_ref k) const { return ::ustl::lower_bound (begin(), end(), k, value_key_compare()); }
inline iterator lower_bound (const_key_ref k) { return const_cast<iterator>(const_cast<rcself_t>(*this).lower_bound (k)); }
const_iterator upper_bound (const_key_ref k) const { return ::ustl::upper_bound (begin(), end(), k, value_key_compare()); }
inline iterator upper_bound (const_key_ref k) { return const_cast<iterator>(const_cast<rcself_t>(*this).upper_bound (k)); }
const_range_t equal_range (const_key_ref k) const { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); }
inline range_t equal_range (const_key_ref k) { return ::ustl::equal_range (begin(), end(), k, value_key_compare()); }
inline size_type count (const_key_ref v) const { const_range_t r = equal_range(v); return distance(r.first,r.second); }
inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); }
inline void push_back (const_reference v) { insert (v); }
inline iterator insert (const_reference v) { return base_class::insert (upper_bound (v.first), v); }
void insert (const_iterator i1, const_iterator i2) { for (; i1 != i2; ++i1) insert (*i1); }
inline void clear (void) { base_class::clear(); }
inline void erase (const_key_ref k) { erase (const_cast<iterator>(lower_bound(k)), const_cast<iterator>(upper_bound(k))); }
inline iterator erase (const_iterator ep) { return base_class::erase (ep); }
inline iterator erase (const_iterator ep1, const_iterator ep2) { return base_class::erase (ep1, ep2); }
inline void swap (multimap& v) { base_class::swap (v); }
#if HAVE_CPP11
using initlist_t = std::initializer_list<value_type>;
inline multimap (multimap&& v) : base_class (move(v)) {}
inline multimap (initlist_t v) : base_class() { insert (v.begin(), v.end()); }
inline multimap& operator= (multimap&& v) { base_class::operator= (move(v)); return *this; }
iterator insert (value_type&& v) { return base_class::insert (upper_bound (v.first), move(v)); }
inline iterator insert (const_iterator, value_type&& v) { return insert(move(v)); }
inline void insert (initlist_t v) { insert (v.begin(), v.end()); }
template <typename... Args>
inline iterator emplace (Args&&... args) { return insert (value_type(forward<Args>(args)...)); }
template <typename... Args>
inline iterator emplace_hint (const_iterator h, Args&&... args) { return insert (h, value_type(forward<Args>(args)...)); }
template <typename... Args>
inline iterator emplace_back (Args&&... args) { return insert (value_type(forward<Args>(args)...)); }
#endif
};
/// Returns the pair<K,V> where K = \p k.
template <typename K, typename V, typename Comp>
inline typename multimap<K,V,Comp>::const_iterator multimap<K,V,Comp>::find (const_key_ref k) const
{
const_iterator i = lower_bound (k);
return (i < end() && Comp()(k, i->first)) ? end() : i;
}
} // namespace ustl

View File

@ -0,0 +1,86 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "uvector.h"
#include "ualgo.h"
namespace ustl {
/// \class multiset umultiset.h ustl.h
/// \ingroup AssociativeContainers
///
/// \brief Multiple sorted container.
/// Unlike set, it may contain multiple copies of each element.
///
template <typename T, typename Comp = less<T> >
class multiset : public vector<T> {
public:
typedef const multiset<T,Comp>& rcself_t;
typedef vector<T> base_class;
typedef typename base_class::value_type value_type;
typedef typename base_class::size_type size_type;
typedef typename base_class::pointer pointer;
typedef typename base_class::const_pointer const_pointer;
typedef typename base_class::reference reference;
typedef typename base_class::const_reference const_reference;
typedef typename base_class::const_iterator const_iterator;
typedef typename base_class::iterator iterator;
typedef typename base_class::reverse_iterator reverse_iterator;
typedef typename base_class::const_reverse_iterator const_reverse_iterator;
typedef pair<iterator,iterator> range_t;
typedef pair<const_iterator,const_iterator> const_range_t;
public:
inline multiset (void) : base_class() {}
inline explicit multiset (size_type n) : base_class (n) {}
inline explicit multiset (rcself_t v) : base_class (v) {}
inline multiset (const_iterator i1, const_iterator i2) : base_class() { insert (i1, i2); }
inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return *this; }
inline size_type size (void) const { return base_class::size(); }
inline iterator begin (void) { return base_class::begin(); }
inline const_iterator begin (void) const { return base_class::begin(); }
inline const_iterator cbegin (void) const { return base_class::cbegin(); }
inline iterator end (void) { return base_class::end(); }
inline const_iterator end (void) const { return base_class::end(); }
inline const_iterator cend (void) const { return base_class::cend(); }
inline Comp value_comp (void) const { return Comp(); }
inline Comp key_comp (void) const { return value_comp(); }
inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); }
inline const_iterator find (const_reference v) const { const_iterator i = ::ustl::lower_bound (begin(), end(), v, Comp()); return (i != end() && *i == v) ? i : end(); }
inline iterator find (const_reference v) { return const_cast<iterator>(const_cast<rcself_t>(*this).find (v)); }
inline const_iterator lower_bound (const_reference v) const { return ::ustl::lower_bound (begin(), end(), v, Comp()); }
inline iterator lower_bound (const_reference v) { return const_cast<iterator>(const_cast<rcself_t>(*this).lower_bound (v)); }
inline const_iterator upper_bound (const_reference v) const { return ::ustl::upper_bound (begin(), end(), v, Comp()); }
inline iterator upper_bound (const_reference v) { return const_cast<iterator>(const_cast<rcself_t>(*this).upper_bound (v)); }
inline const_range_t equal_range (const_reference v) const { return ::ustl::equal_range (begin(), end(), v, Comp()); }
inline range_t equal_range (const_reference v) { return ::ustl::equal_range (begin(), end(), v, Comp()); }
inline size_type count (const_reference v) const { const_range_t r = equal_range(v); return distance(r.first,r.second); }
inline void push_back (const_reference v) { insert (v); }
inline iterator insert (const_reference v) { return base_class::insert (upper_bound(v), v); }
inline iterator insert (const_iterator, const_reference v) { return insert(v); }
void insert (const_iterator i1, const_iterator i2) { for (; i1 < i2; ++i1) insert (*i1); }
inline iterator erase (const_iterator ep) { return base_class::erase (ep); }
inline iterator erase (const_iterator ep1, const_iterator ep2) { return base_class::erase (ep1, ep2); }
inline size_type erase (const_reference v) { range_t epr = equal_range (v); erase (epr.first, epr.second); return distance(epr.first, epr.second); }
inline void clear (void) { base_class::clear(); }
inline void swap (multiset& v) { base_class::swap (v); }
#if HAVE_CPP11
using initlist_t = std::initializer_list<value_type>;
inline explicit multiset (multiset&& v) : base_class (move(v)) {}
inline multiset (initlist_t v) : base_class() { insert (v.begin(), v.end()); }
inline multiset& operator= (multiset&& v) { base_class::operator= (move(v)); return *this; }
inline iterator insert (T&& v) { return base_class::insert (upper_bound(v), move(v)); }
inline iterator insert (const_iterator, T&& v) { return insert (move(v)); }
inline void insert (initlist_t v) { insert (v.begin(), v.end()); }
template <typename... Args>
inline iterator emplace (Args&&... args) { return insert (T(forward<Args>(args)...)); }
template <typename... Args>
inline iterator emplace_hint (const_iterator h, Args&&... args) { return insert (h, T(forward<Args>(args)...)); }
template <typename... Args>
inline iterator emplace_back (Args&&... args) { return insert (T(forward<Args>(args)...)); }
#endif
};
} // namespace ustl

View File

@ -0,0 +1 @@
#include <new.h>

View File

@ -0,0 +1,151 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
namespace ustl {
/// Returns the sum of all elements in [first, last) added to \p init.
/// \ingroup NumericAlgorithms
///
template <typename InputIterator, typename T>
inline T accumulate (InputIterator first, InputIterator last, T init)
{
while (first < last)
init += *first++;
return init;
}
/// Returns the sum of all elements in [first, last) via \p op, added to \p init.
/// \ingroup NumericAlgorithms
///
template <typename InputIterator, typename T, typename BinaryFunction>
inline T accumulate (InputIterator first, InputIterator last, T init, BinaryFunction binary_op)
{
while (first < last)
init = binary_op (init, *first++);
return init;
}
/// Assigns range [value, value + (last - first)) to [first, last)
/// \ingroup NumericAlgorithms
///
template <typename ForwardIterator, typename T>
inline void iota (ForwardIterator first, ForwardIterator last, T value)
{
while (first < last)
*first++ = value++;
}
/// Returns the sum of products of respective elements in the given ranges.
/// \ingroup NumericAlgorithms
///
template <typename InputIterator1, typename InputIterator2, typename T>
inline T inner_product (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init)
{
while (first1 < last1)
init += *first1++ * *first2++;
return init;
}
/// Returns the sum of products of respective elements in the given ranges.
/// \ingroup NumericAlgorithms
///
template <typename InputIterator1, typename InputIterator2, typename T,
typename BinaryOperation1, typename BinaryOperation2>
inline T inner_product
(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init,
BinaryOperation1 sumOp, BinaryOperation2 productOp)
{
while (first1 < last1)
init = sumOp (init, productOp (*first1++, *first2++));
return init;
}
/// Writes result such that result[i] = sum (first...first+i)
/// \ingroup NumericAlgorithms
///
template <typename InputIterator, typename OutputIterator>
inline OutputIterator partial_sum (InputIterator first, InputIterator last, OutputIterator result)
{
if (first < last)
*result = *first++;
while (first < last)
*++result = *first++ + *result;
return result;
}
/// Writes result such that result[i] = sumOp (first...first+i)
/// \ingroup NumericAlgorithms
///
template <typename InputIterator, typename OutputIterator, typename BinaryOperation>
inline OutputIterator partial_sum (InputIterator first, InputIterator last, OutputIterator result, BinaryOperation sumOp)
{
if (first < last)
*result = *first++;
while (first < last)
*++result = sumOp (*first++, *result);
return result;
}
/// Writes result such that result[i] = first[i] - first[i - 1]
/// \ingroup NumericAlgorithms
///
template <typename InputIterator, typename OutputIterator>
inline OutputIterator adjacent_difference (InputIterator first, InputIterator last, OutputIterator result)
{
if (first < last)
*result++ = *first++;
while (first < last)
*result++ = *first - *(first - 1);
return result;
}
/// Writes result such that result[i] = differenceOp (first[i], first[i - 1])
/// \ingroup NumericAlgorithms
///
template <typename InputIterator, typename OutputIterator, typename BinaryOperation>
inline OutputIterator adjacent_difference (InputIterator first, InputIterator last, OutputIterator result, BinaryOperation differenceOp)
{
if (first < last)
*result++ = *first++;
while (first < last)
*result++ = differenceOp (*first, *(first - 1));
return result;
}
/// \brief Returns x^n.
/// Donald Knuth's Russian Peasant algorithm.
/// \ingroup NumericAlgorithms
///
template <typename T>
inline T power (T x, unsigned n)
{
T result (n % 2 ? x : 1);
while (n /= 2) {
x *= x;
if (n % 2)
result *= x;
}
return result;
}
/// \brief Returns x^n, using \p op instead of multiplication.
/// Donald Knuth's Russian Peasant algorithm.
/// \ingroup NumericAlgorithms
///
template <typename T, typename BinaryOperation>
inline T power (T x, unsigned n, BinaryOperation op)
{
T result (n % 2 ? x : 1);
while (n /= 2) {
x = op (x, x);
if (n % 2)
result = op (result, x);
}
return result;
}
} // namespace ustl

View File

@ -0,0 +1,73 @@
// This file is part of the uSTL library, an STL implementation.
//
// Copyright (c) 2005 by Mike Sharov <msharov@users.sourceforge.net>
// This file is free software, distributed under the MIT License.
#pragma once
#include "ualgobase.h"
namespace ustl {
class istream;
class ostream;
class ostringstream;
/// \class pair upair.h ustl.h
/// \ingroup AssociativeContainers
///
/// \brief Container for two values.
///
template <typename T1, typename T2>
class pair {
public:
typedef T1 first_type;
typedef T2 second_type;
public:
/// Default constructor.
inline constexpr pair (void) : first (T1()), second (T2()) {}
/// Initializes members with \p a, and \p b.
inline pair (const T1& a, const T2& b) : first (a), second (b) {}
template <typename T3, typename T4>
inline pair (const pair<T3,T4>& p2) : first (p2.first), second (p2.second) {}
inline pair& operator= (const pair& p2) { first = p2.first; second = p2.second; return *this; }
template <typename T3, typename T4>
inline pair& operator= (const pair<T3,T4>& p2) { first = p2.first; second = p2.second; return *this; }
inline bool operator== (const pair& v)const { return first == v.first && second == v.second; }
inline bool operator< (const pair& v) const { return first < v.first || (first == v.first && second < v.second); }
inline void swap (pair& v) { ::ustl::swap(first,v.first); ::ustl::swap(second,v.second); }
inline void read (istream& is);
inline void write (ostream& os) const;
void text_write (ostringstream& os) const;
inline size_t stream_size (void) const;
#if HAVE_CPP11
pair (const pair&) = default;
pair (pair&&) = default;
template <typename T3, typename T4>
inline pair (T3&& a, T4&& b) : first (forward<T3>(a)), second (forward<T4>(b)) {}
template <typename T3, typename T4>
inline pair (pair<T3,T4>&& p2) : first (forward<T3>(p2.first)), second (forward<T4>(p2.second)) {}
inline pair& operator= (pair&& p2) { first = move(p2.first); second = move(p2.second); return *this; }
template <typename T3, typename T4>
inline pair& operator= (pair<T3,T4>&& p2) { first = forward<T3>(p2.first); second = forward<T4>(p2.second); return *this; }
inline void swap (pair&& v) { ::ustl::swap(first,v.first); ::ustl::swap(second,v.second); }
#endif
public:
first_type first;
second_type second;
};
#if HAVE_CPP11
/// Returns a pair object with (a,b)
template <typename T1, typename T2>
inline constexpr pair<T1,T2> make_pair (T1&& a, T2&& b)
{ return pair<T1,T2> (forward<T1>(a), forward<T2>(b)); }
#endif
/// Returns a pair object with (a,b)
template <typename T1, typename T2>
inline constexpr pair<T1,T2> make_pair (const T1& a, const T2& b)
{ return pair<T1,T2> (a, b); }
} // namespace ustl

Some files were not shown because too many files have changed in this diff Show More