Ronald Kinard
8 years ago
committed by
GitHub
14 changed files with 247 additions and 391 deletions
@ -1,14 +0,0 @@ |
|||||||
[package] |
|
||||||
name = "ctr-libc" |
|
||||||
version = "0.1.0" |
|
||||||
authors = ["Fenrir <fenrirwolf@gmail.com>", "The Rust Project Developers"] |
|
||||||
license = "MIT/Apache 2.0" |
|
||||||
|
|
||||||
description = """ |
|
||||||
A library for types and bindings to native C functions found in newlib |
|
||||||
for devkitARM |
|
||||||
""" |
|
||||||
|
|
||||||
[features] |
|
||||||
default = ["use_std"] |
|
||||||
use_std = [] |
|
@ -1 +0,0 @@ |
|||||||
Extended libc bindings for use with ctr-std. This library is experimental. Use of some functions might result in undefined symbols. |
|
@ -1,131 +0,0 @@ |
|||||||
// Many of these constants are unused/unnecessary. But let's keep them around for now.
|
|
||||||
|
|
||||||
pub const STDIN_FILENO: ::c_int = 0; |
|
||||||
pub const STDOUT_FILENO: ::c_int = 1; |
|
||||||
pub const STDERR_FILENO: ::c_int = 2; |
|
||||||
|
|
||||||
pub const EPERM: ::c_int = 1; |
|
||||||
pub const ENOENT: ::c_int = 2; |
|
||||||
pub const ESRCH: ::c_int = 3; |
|
||||||
pub const EINTR: ::c_int = 4; |
|
||||||
pub const EIO: ::c_int = 5; |
|
||||||
pub const ENXIO: ::c_int = 6; |
|
||||||
pub const E2BIG: ::c_int = 7; |
|
||||||
pub const ENOEXEC: ::c_int = 8; |
|
||||||
pub const EBADF: ::c_int = 9; |
|
||||||
pub const ECHILD: ::c_int = 10; |
|
||||||
pub const EAGAIN: ::c_int = 11; |
|
||||||
pub const ENOMEM: ::c_int = 12; |
|
||||||
pub const EACCES: ::c_int = 13; |
|
||||||
pub const EFAULT: ::c_int = 14; |
|
||||||
pub const EBUSY: ::c_int = 16; |
|
||||||
pub const EEXIST: ::c_int = 17; |
|
||||||
pub const EXDEV: ::c_int = 18; |
|
||||||
pub const ENODEV: ::c_int = 19; |
|
||||||
pub const ENOTDIR: ::c_int = 20; |
|
||||||
pub const EISDIR: ::c_int = 21; |
|
||||||
pub const EINVAL: ::c_int = 22; |
|
||||||
pub const ENFILE: ::c_int = 23; |
|
||||||
pub const EMFILE: ::c_int = 24; |
|
||||||
pub const ENOTTY: ::c_int = 25; |
|
||||||
pub const ETXTBSY: ::c_int = 26; |
|
||||||
pub const EFBIG: ::c_int = 27; |
|
||||||
pub const ENOSPC: ::c_int = 28; |
|
||||||
pub const ESPIPE: ::c_int = 29; |
|
||||||
pub const EROFS: ::c_int = 30; |
|
||||||
pub const EMLINK: ::c_int = 31; |
|
||||||
pub const EPIPE: ::c_int = 32; |
|
||||||
pub const EDOM: ::c_int = 33; |
|
||||||
pub const ERANGE: ::c_int = 34; |
|
||||||
pub const ENOMSG: ::c_int = 35; |
|
||||||
pub const EIDRM: ::c_int = 36; |
|
||||||
pub const EDEADLK: ::c_int = 45; |
|
||||||
pub const ENOLCK: ::c_int = 46; |
|
||||||
pub const ENOSTR: ::c_int = 60; |
|
||||||
pub const ENODATA: ::c_int = 61; |
|
||||||
pub const ETIME: ::c_int = 62; |
|
||||||
pub const ENOSR: ::c_int = 63; |
|
||||||
pub const ENOLINK: ::c_int = 67; |
|
||||||
pub const EPROTO: ::c_int = 71; |
|
||||||
pub const EMULTIHOP: ::c_int = 74; |
|
||||||
pub const EBADMSG: ::c_int = 77; |
|
||||||
pub const EFTYPE: ::c_int = 79; |
|
||||||
pub const ENOSYS: ::c_int = 88; |
|
||||||
pub const ENOTEMPTY: ::c_int = 90; |
|
||||||
pub const ENAMETOOLONG: ::c_int = 91; |
|
||||||
pub const ELOOP: ::c_int = 92; |
|
||||||
pub const EOPNOTSUPP: ::c_int = 95; |
|
||||||
pub const EPFNOSUPPORT: ::c_int = 96; |
|
||||||
pub const ECONNRESET: ::c_int = 104; |
|
||||||
pub const ENOBUFS: ::c_int = 105; |
|
||||||
pub const EAFNOSUPPORT: ::c_int = 106; |
|
||||||
pub const EPROTOTYPE: ::c_int = 107; |
|
||||||
pub const ENOTSOCK: ::c_int = 108; |
|
||||||
pub const ENOPROTOOPT: ::c_int = 109; |
|
||||||
pub const ECONNREFUSED: ::c_int = 111; |
|
||||||
pub const EADDRINUSE: ::c_int = 112; |
|
||||||
pub const ECONNABORTED: ::c_int = 113; |
|
||||||
pub const ENETUNREACH: ::c_int = 114; |
|
||||||
pub const ENETDOWN: ::c_int = 115; |
|
||||||
pub const ETIMEDOUT: ::c_int = 116; |
|
||||||
pub const EHOSTDOWN: ::c_int = 117; |
|
||||||
pub const EHOSTUNREACH: ::c_int = 118; |
|
||||||
pub const EINPROGRESS: ::c_int = 119; |
|
||||||
pub const EALREADY: ::c_int = 120; |
|
||||||
pub const EDESTADDRREQ: ::c_int = 121; |
|
||||||
pub const EMSGSIZE: ::c_int = 122; |
|
||||||
pub const EPROTONOSUPPORT: ::c_int = 123; |
|
||||||
pub const EADDRNOTAVAIL: ::c_int = 125; |
|
||||||
pub const ENETRESET: ::c_int = 126; |
|
||||||
pub const EISCONN: ::c_int = 127; |
|
||||||
pub const ENOTCONN: ::c_int = 128; |
|
||||||
pub const ETOOMANYREFS: ::c_int = 129; |
|
||||||
pub const EDQUOT: ::c_int = 132; |
|
||||||
pub const ESTALE: ::c_int = 133; |
|
||||||
pub const ENOTSUP: ::c_int = 134; |
|
||||||
pub const EILSEQ: ::c_int = 138; |
|
||||||
pub const EOVERFLOW: ::c_int = 139; |
|
||||||
pub const ECANCELED: ::c_int = 140; |
|
||||||
pub const ENOTRECOVERABLE: ::c_int = 141; |
|
||||||
pub const EOWNERDEAD: ::c_int = 142; |
|
||||||
pub const EWOULDBLOCK: ::c_int = 11; |
|
||||||
pub const __ELASTERROR: ::c_int = 2000; |
|
||||||
|
|
||||||
pub const O_RDONLY: ::c_int = 0; |
|
||||||
pub const O_WRONLY: ::c_int = 1; |
|
||||||
pub const O_RDWR: ::c_int = 2; |
|
||||||
pub const O_APPEND: ::c_int = 8; |
|
||||||
pub const O_CREAT: ::c_int = 512; |
|
||||||
pub const O_TRUNC: ::c_int = 1024; |
|
||||||
pub const O_EXCL: ::c_int = 2048; |
|
||||||
pub const O_SYNC: ::c_int = 8192; |
|
||||||
pub const O_NONBLOCK: ::c_int = 16384; |
|
||||||
pub const O_NOCTTY: ::c_int = 32768; |
|
||||||
pub const FD_CLOEXEC: ::c_int = 1; |
|
||||||
|
|
||||||
pub const S_IFIFO: ::mode_t = 4096; |
|
||||||
pub const S_IFCHR: ::mode_t = 8192; |
|
||||||
pub const S_IFDIR: ::mode_t = 16384; |
|
||||||
pub const S_IFBLK: ::mode_t = 24576; |
|
||||||
pub const S_IFREG: ::mode_t = 32768; |
|
||||||
pub const S_IFLNK: ::mode_t = 40960; |
|
||||||
pub const S_IFSOCK: ::mode_t = 49152; |
|
||||||
pub const S_IFMT: ::mode_t = 61440; |
|
||||||
|
|
||||||
pub const DT_FIFO: u8 = 1; |
|
||||||
pub const DT_CHR: u8 = 2; |
|
||||||
pub const DT_DIR: u8 = 4; |
|
||||||
pub const DT_BLK: u8 = 6; |
|
||||||
pub const DT_REG: u8 = 8; |
|
||||||
pub const DT_LNK: u8 = 10; |
|
||||||
pub const DT_SOCK: u8 = 12; |
|
||||||
|
|
||||||
pub const O_CLOEXEC: ::c_int = 0x80000; |
|
||||||
pub const O_ACCMODE: ::c_int = 3; |
|
||||||
|
|
||||||
pub const SEEK_SET: ::c_int = 0; |
|
||||||
pub const SEEK_CUR: ::c_int = 1; |
|
||||||
pub const SEEK_END: ::c_int = 2; |
|
||||||
|
|
||||||
pub const SIG_IGN: ::sighandler_t = 1 as ::sighandler_t; |
|
||||||
pub const SIGPIPE: ::c_int = 13; |
|
@ -1,39 +0,0 @@ |
|||||||
extern "C" { |
|
||||||
pub fn abort() -> !; |
|
||||||
pub fn chdir(dir: *const ::c_char) -> ::c_int; |
|
||||||
pub fn chmod(path: *const ::c_char, mode: ::mode_t) -> ::c_int; |
|
||||||
pub fn close(fd: ::c_int) -> ::c_int; |
|
||||||
pub fn closedir(dirp: *mut ::DIR) -> ::c_int; |
|
||||||
pub fn exit(status: ::c_int) -> !; |
|
||||||
pub fn fchmod(fd: ::c_int, mode: ::mode_t) -> ::c_int; |
|
||||||
pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int; |
|
||||||
pub fn fdatasync(fd: ::c_int) -> ::c_int; |
|
||||||
pub fn free(p: *mut ::c_void); |
|
||||||
pub fn fstat(fildes: ::c_int, buf: *mut ::stat) -> ::c_int; |
|
||||||
pub fn ftruncate(fd: ::c_int, length: ::off_t) -> ::c_int; |
|
||||||
pub fn fsync(fd: ::c_int) -> ::c_int; |
|
||||||
pub fn getcwd(buf: *mut ::c_char, size: ::size_t) -> *mut ::c_char; |
|
||||||
pub fn gettimeofday(tp: *mut ::timeval, tz: *mut ::c_void) -> ::c_int; |
|
||||||
pub fn link(src: *const ::c_char, dst: *const ::c_char) -> ::c_int; |
|
||||||
pub fn lstat(path: *const ::c_char, buf: *mut ::stat) -> ::c_int; |
|
||||||
pub fn lseek(fd: ::c_int, offset: ::off_t, whence: ::c_int) -> ::off_t; |
|
||||||
pub fn memchr(cx: *const ::c_void, c: ::c_int, n: ::size_t) -> *mut ::c_void; |
|
||||||
pub fn memrchr(cx: *const ::c_void, c: ::c_int, n: ::size_t) -> *mut ::c_void; |
|
||||||
pub fn mkdir(path: *const ::c_char, mode: ::mode_t) -> ::c_int; |
|
||||||
pub fn open(path: *const ::c_char, oflag: ::c_int, ...) -> ::c_int; |
|
||||||
pub fn opendir(dirname: *const ::c_char) -> *mut ::DIR; |
|
||||||
pub fn pread(fd: ::c_int, buf: *mut ::c_void, count: ::size_t, offset: ::off_t) -> ::ssize_t; |
|
||||||
pub fn pwrite(fd: ::c_int, buf: *const ::c_void, count: ::size_t, offset: ::off_t) -> ::ssize_t; |
|
||||||
pub fn read(fd: ::c_int, puf: *mut ::c_void, count: ::size_t) -> ::ssize_t; |
|
||||||
pub fn readlink(path: *const ::c_char, buf: *mut ::c_char, bufsz: ::size_t) -> ::ssize_t; |
|
||||||
pub fn readdir_r(dirp: *mut ::DIR, entry: *mut ::dirent, result: *mut *mut ::dirent) -> ::c_int; |
|
||||||
pub fn realpath(pathname: *const ::c_char, resolved: *mut ::c_char) -> *mut ::c_char; |
|
||||||
pub fn rename(oldname: *const ::c_char, newname: *const ::c_char) -> ::c_int; |
|
||||||
pub fn rmdir(path: *const ::c_char) -> ::c_int; |
|
||||||
pub fn signal(signum: ::c_int, handler: ::sighandler_t) -> ::sighandler_t; |
|
||||||
pub fn stat(path: *const ::c_char, buf: *mut ::stat) -> ::c_int; |
|
||||||
pub fn strlen(cs: *const ::c_char) -> ::size_t; |
|
||||||
pub fn symlink(path1: *const ::c_char, path2: *const ::c_char) -> ::c_int; |
|
||||||
pub fn unlink(c: *const ::c_char) -> ::c_int; |
|
||||||
pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t) -> ::ssize_t; |
|
||||||
} |
|
@ -1,177 +0,0 @@ |
|||||||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
|
||||||
// file at the top-level directory of this distribution and at
|
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
||||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
||||||
// option. This file may not be copied, modified, or distributed
|
|
||||||
// except according to those terms.
|
|
||||||
|
|
||||||
#![allow(bad_style, overflowing_literals, improper_ctypes, non_camel_case_types)] |
|
||||||
|
|
||||||
#![no_std] |
|
||||||
|
|
||||||
mod constants; |
|
||||||
mod functions; |
|
||||||
pub use constants::*; |
|
||||||
pub use functions::*; |
|
||||||
|
|
||||||
#[link(name = "c")] |
|
||||||
#[link(name = "m")] |
|
||||||
extern {} |
|
||||||
|
|
||||||
#[repr(u8)] |
|
||||||
pub enum c_void { |
|
||||||
__variant1, |
|
||||||
__variant2, |
|
||||||
} |
|
||||||
|
|
||||||
// char is u8 on ARM
|
|
||||||
pub type c_char = u8; |
|
||||||
pub type c_schar = i8; |
|
||||||
pub type c_uchar = u8; |
|
||||||
pub type c_short = i16; |
|
||||||
pub type c_ushort = u16; |
|
||||||
pub type c_int = i32; |
|
||||||
pub type c_uint = u32; |
|
||||||
pub type c_float = f32; |
|
||||||
pub type c_double = f64; |
|
||||||
pub type c_longlong = i64; |
|
||||||
pub type c_ulonglong = u64; |
|
||||||
|
|
||||||
// 4 bytes on ARM
|
|
||||||
pub type c_long = i32; |
|
||||||
pub type c_ulong = u32; |
|
||||||
|
|
||||||
pub type size_t = usize; |
|
||||||
pub type ptrdiff_t = isize; |
|
||||||
pub type intptr_t = isize; |
|
||||||
pub type uintptr_t = usize; |
|
||||||
pub type ssize_t = isize; |
|
||||||
|
|
||||||
// devkitARM says wchar_t is 4 bytes. Nintendo's API says it's 2 bytes.
|
|
||||||
// hope you never have to interact between the two...
|
|
||||||
pub type wchar_t = c_int; |
|
||||||
|
|
||||||
pub type int8_t = i8; |
|
||||||
pub type uint8_t = u8; |
|
||||||
pub type int16_t = i16; |
|
||||||
pub type uint16_t = u16; |
|
||||||
pub type int32_t = i32; |
|
||||||
pub type uint32_t = u32; |
|
||||||
pub type int64_t = i64; |
|
||||||
pub type uint64_t = u64; |
|
||||||
|
|
||||||
pub type time_t = i32; |
|
||||||
pub type clockid_t = c_int; |
|
||||||
pub type mode_t = u32; |
|
||||||
pub type sighandler_t = size_t; |
|
||||||
pub type dev_t = u32; |
|
||||||
pub type nlink_t = u32; |
|
||||||
pub type uid_t = u32; |
|
||||||
pub type gid_t = u32; |
|
||||||
pub type off_t = i64; |
|
||||||
pub type blksize_t = i32; |
|
||||||
pub type blkcnt_t = c_ulong; |
|
||||||
pub type fsblkcnt_t = uint64_t; |
|
||||||
pub type fsfilcnt_t = uint32_t; |
|
||||||
pub type ino_t = u32; |
|
||||||
pub type suseconds_t = i32; |
|
||||||
pub type error_t = c_int; |
|
||||||
|
|
||||||
pub enum timezone {} |
|
||||||
|
|
||||||
pub enum _reent {} |
|
||||||
|
|
||||||
#[repr(C)] |
|
||||||
#[derive(Copy, Clone)] |
|
||||||
#[derive(Debug)] |
|
||||||
pub struct timeval { |
|
||||||
pub tv_sec: time_t, |
|
||||||
pub tv_usec: suseconds_t, |
|
||||||
} |
|
||||||
|
|
||||||
#[repr(C)] |
|
||||||
#[derive(Copy, Clone)] |
|
||||||
#[derive(Debug)] |
|
||||||
pub struct timespec { |
|
||||||
pub tv_sec: time_t, |
|
||||||
pub tv_nsec: c_long, |
|
||||||
} |
|
||||||
|
|
||||||
#[repr(C)] |
|
||||||
#[derive(Copy, Clone)] |
|
||||||
#[derive(Debug)] |
|
||||||
pub struct itimerspec { |
|
||||||
pub it_interval: timespec, |
|
||||||
pub it_value: timespec, |
|
||||||
} |
|
||||||
|
|
||||||
#[repr(C)] |
|
||||||
#[derive(Copy, Clone)] |
|
||||||
#[derive(Debug)] |
|
||||||
pub struct tm { |
|
||||||
pub tm_sec: c_int, |
|
||||||
pub tm_min: c_int, |
|
||||||
pub tm_hour: c_int, |
|
||||||
pub tm_mday: c_int, |
|
||||||
pub tm_mon: c_int, |
|
||||||
pub tm_year: c_int, |
|
||||||
pub tm_wday: c_int, |
|
||||||
pub tm_yday: c_int, |
|
||||||
pub tm_isdst: c_int, |
|
||||||
} |
|
||||||
|
|
||||||
pub enum DIR {} |
|
||||||
|
|
||||||
#[repr(C)] |
|
||||||
#[derive(Copy, Clone)] |
|
||||||
#[derive(Debug)] |
|
||||||
pub struct stat { |
|
||||||
pub st_dev: dev_t, |
|
||||||
pub st_ino: ino_t, |
|
||||||
pub st_mode: mode_t, |
|
||||||
pub st_nlink: nlink_t, |
|
||||||
pub st_uid: uid_t, |
|
||||||
pub st_gid: gid_t, |
|
||||||
pub st_rdev: dev_t, |
|
||||||
pub st_size: off_t, |
|
||||||
pub st_atime: time_t, |
|
||||||
pub st_spare1: c_long, |
|
||||||
pub st_mtime: time_t, |
|
||||||
pub st_spare2: c_long, |
|
||||||
pub st_ctime: time_t, |
|
||||||
pub st_spare3: c_long, |
|
||||||
pub st_blksize: blksize_t, |
|
||||||
pub st_blocks: blkcnt_t, |
|
||||||
pub st_spare4: [c_long; 2usize], |
|
||||||
} |
|
||||||
|
|
||||||
#[repr(C)] |
|
||||||
#[derive(Copy, Clone)] |
|
||||||
#[derive(Debug)] |
|
||||||
pub struct statvfs { |
|
||||||
pub f_bsize: c_ulong, |
|
||||||
pub f_frsize: c_ulong, |
|
||||||
pub f_blocks: fsblkcnt_t, |
|
||||||
pub f_bfree: fsblkcnt_t, |
|
||||||
pub f_bavail: fsblkcnt_t, |
|
||||||
pub f_files: fsfilcnt_t, |
|
||||||
pub f_ffree: fsfilcnt_t, |
|
||||||
pub f_favail: fsfilcnt_t, |
|
||||||
pub f_fsid: c_ulong, |
|
||||||
pub f_flag: c_ulong, |
|
||||||
pub f_namemax: c_ulong, |
|
||||||
} |
|
||||||
|
|
||||||
#[repr(C)] |
|
||||||
#[derive(Copy)] |
|
||||||
pub struct dirent { |
|
||||||
pub d_ino: ino_t, |
|
||||||
pub d_type: c_uchar, |
|
||||||
pub d_name: [c_char; 256usize], |
|
||||||
} |
|
||||||
impl Clone for dirent { |
|
||||||
fn clone(&self) -> Self { *self } |
|
||||||
} |
|
@ -0,0 +1,230 @@ |
|||||||
|
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
//
|
||||||
|
// Original implementation taken from rust-memchr
|
||||||
|
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
|
||||||
|
|
||||||
|
#[allow(dead_code)] |
||||||
|
pub mod fallback { |
||||||
|
use cmp; |
||||||
|
use mem; |
||||||
|
|
||||||
|
const LO_U64: u64 = 0x0101010101010101; |
||||||
|
const HI_U64: u64 = 0x8080808080808080; |
||||||
|
|
||||||
|
// use truncation
|
||||||
|
const LO_USIZE: usize = LO_U64 as usize; |
||||||
|
const HI_USIZE: usize = HI_U64 as usize; |
||||||
|
|
||||||
|
/// Return `true` if `x` contains any zero byte.
|
||||||
|
///
|
||||||
|
/// From *Matters Computational*, J. Arndt
|
||||||
|
///
|
||||||
|
/// "The idea is to subtract one from each of the bytes and then look for
|
||||||
|
/// bytes where the borrow propagated all the way to the most significant
|
||||||
|
/// bit."
|
||||||
|
#[inline] |
||||||
|
fn contains_zero_byte(x: usize) -> bool { |
||||||
|
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "32")] |
||||||
|
#[inline] |
||||||
|
fn repeat_byte(b: u8) -> usize { |
||||||
|
let mut rep = (b as usize) << 8 | b as usize; |
||||||
|
rep = rep << 16 | rep; |
||||||
|
rep |
||||||
|
} |
||||||
|
|
||||||
|
#[cfg(target_pointer_width = "64")] |
||||||
|
#[inline] |
||||||
|
fn repeat_byte(b: u8) -> usize { |
||||||
|
let mut rep = (b as usize) << 8 | b as usize; |
||||||
|
rep = rep << 16 | rep; |
||||||
|
rep = rep << 32 | rep; |
||||||
|
rep |
||||||
|
} |
||||||
|
|
||||||
|
/// Return the first index matching the byte `a` in `text`.
|
||||||
|
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> { |
||||||
|
// Scan for a single byte value by reading two `usize` words at a time.
|
||||||
|
//
|
||||||
|
// Split `text` in three parts
|
||||||
|
// - unaligned initial part, before the first word aligned address in text
|
||||||
|
// - body, scan by 2 words at a time
|
||||||
|
// - the last remaining part, < 2 word size
|
||||||
|
let len = text.len(); |
||||||
|
let ptr = text.as_ptr(); |
||||||
|
let usize_bytes = mem::size_of::<usize>(); |
||||||
|
|
||||||
|
// search up to an aligned boundary
|
||||||
|
let align = (ptr as usize) & (usize_bytes- 1); |
||||||
|
let mut offset; |
||||||
|
if align > 0 { |
||||||
|
offset = cmp::min(usize_bytes - align, len); |
||||||
|
if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { |
||||||
|
return Some(index); |
||||||
|
} |
||||||
|
} else { |
||||||
|
offset = 0; |
||||||
|
} |
||||||
|
|
||||||
|
// search the body of the text
|
||||||
|
let repeated_x = repeat_byte(x); |
||||||
|
|
||||||
|
if len >= 2 * usize_bytes { |
||||||
|
while offset <= len - 2 * usize_bytes { |
||||||
|
unsafe { |
||||||
|
let u = *(ptr.offset(offset as isize) as *const usize); |
||||||
|
let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize); |
||||||
|
|
||||||
|
// break if there is a matching byte
|
||||||
|
let zu = contains_zero_byte(u ^ repeated_x); |
||||||
|
let zv = contains_zero_byte(v ^ repeated_x); |
||||||
|
if zu || zv { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
offset += usize_bytes * 2; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// find the byte after the point the body loop stopped
|
||||||
|
text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) |
||||||
|
} |
||||||
|
|
||||||
|
/// Return the last index matching the byte `a` in `text`.
|
||||||
|
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> { |
||||||
|
// Scan for a single byte value by reading two `usize` words at a time.
|
||||||
|
//
|
||||||
|
// Split `text` in three parts
|
||||||
|
// - unaligned tail, after the last word aligned address in text
|
||||||
|
// - body, scan by 2 words at a time
|
||||||
|
// - the first remaining bytes, < 2 word size
|
||||||
|
let len = text.len(); |
||||||
|
let ptr = text.as_ptr(); |
||||||
|
let usize_bytes = mem::size_of::<usize>(); |
||||||
|
|
||||||
|
// search to an aligned boundary
|
||||||
|
let end_align = (ptr as usize + len) & (usize_bytes - 1); |
||||||
|
let mut offset; |
||||||
|
if end_align > 0 { |
||||||
|
offset = if end_align >= len { 0 } else { len - end_align }; |
||||||
|
if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { |
||||||
|
return Some(offset + index); |
||||||
|
} |
||||||
|
} else { |
||||||
|
offset = len; |
||||||
|
} |
||||||
|
|
||||||
|
// search the body of the text
|
||||||
|
let repeated_x = repeat_byte(x); |
||||||
|
|
||||||
|
while offset >= 2 * usize_bytes { |
||||||
|
unsafe { |
||||||
|
let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize); |
||||||
|
let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize); |
||||||
|
|
||||||
|
// break if there is a matching byte
|
||||||
|
let zu = contains_zero_byte(u ^ repeated_x); |
||||||
|
let zv = contains_zero_byte(v ^ repeated_x); |
||||||
|
if zu || zv { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
offset -= 2 * usize_bytes; |
||||||
|
} |
||||||
|
|
||||||
|
// find the byte before the point the body loop stopped
|
||||||
|
text[..offset].iter().rposition(|elt| *elt == x) |
||||||
|
} |
||||||
|
|
||||||
|
// test fallback implementations on all platforms
|
||||||
|
#[test] |
||||||
|
fn matches_one() { |
||||||
|
assert_eq!(Some(0), memchr(b'a', b"a")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_begin() { |
||||||
|
assert_eq!(Some(0), memchr(b'a', b"aaaa")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_end() { |
||||||
|
assert_eq!(Some(4), memchr(b'z', b"aaaaz")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_nul() { |
||||||
|
assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_past_nul() { |
||||||
|
assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn no_match_empty() { |
||||||
|
assert_eq!(None, memchr(b'a', b"")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn no_match() { |
||||||
|
assert_eq!(None, memchr(b'a', b"xyz")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_one_reversed() { |
||||||
|
assert_eq!(Some(0), memrchr(b'a', b"a")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_begin_reversed() { |
||||||
|
assert_eq!(Some(3), memrchr(b'a', b"aaaa")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_end_reversed() { |
||||||
|
assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_nul_reversed() { |
||||||
|
assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn matches_past_nul_reversed() { |
||||||
|
assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn no_match_empty_reversed() { |
||||||
|
assert_eq!(None, memrchr(b'a', b"")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn no_match_reversed() { |
||||||
|
assert_eq!(None, memrchr(b'a', b"xyz")); |
||||||
|
} |
||||||
|
|
||||||
|
#[test] |
||||||
|
fn each_alignment_reversed() { |
||||||
|
let mut data = [1u8; 64]; |
||||||
|
let needle = 2; |
||||||
|
let pos = 40; |
||||||
|
data[pos] = needle; |
||||||
|
for start in 0..16 { |
||||||
|
assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue