Add support for writing file by path
This commit is contained in:
+68
-26
@@ -89,7 +89,7 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
void setName(const char *name) {
|
void setName(const char *name) {
|
||||||
auto data = getName();
|
auto data = getName();
|
||||||
auto nameLen = ox_strlen(name);
|
auto nameLen = ox_strlen(name);
|
||||||
ox_memcpy(data, &name, nameLen);
|
ox_memcpy(data, name, nameLen);
|
||||||
data[nameLen] = 0;
|
data[nameLen] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t spaceNeeded(const char *fileName) {
|
static uint64_t spaceNeeded(const char *fileName) {
|
||||||
return sizeof(DirectoryEntry) + ox_strlen(fileName);
|
return sizeof(DirectoryEntry) + ox_strlen(fileName) + 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
/**
|
/**
|
||||||
* Number of files in this directory.
|
* Number of files in this directory.
|
||||||
*/
|
*/
|
||||||
typename FileStore::InodeId_t size = 0;
|
typename FileStore::FsSize_t size = 0;
|
||||||
|
|
||||||
DirectoryEntry *files() {
|
DirectoryEntry *files() {
|
||||||
return size ? (DirectoryEntry*) (this + 1) : nullptr;
|
return size ? (DirectoryEntry*) (this + 1) : nullptr;
|
||||||
@@ -161,7 +161,7 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
static uint8_t *format(void *buffer, typename FileStore::FsSize_t size, bool useDirectories);
|
static uint8_t *format(void *buffer, typename FileStore::FsSize_t size, bool useDirectories);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int insertDirectoryEntry(uint64_t inode, const char *dirPath, const char *fileName);
|
int insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename FileStore, FsType FS_TYPE>
|
template<typename FileStore, FsType FS_TYPE>
|
||||||
@@ -179,7 +179,12 @@ int FileSystemTemplate<FileStore, FS_TYPE>::mkdir(const char *path) {
|
|||||||
|
|
||||||
template<typename FileStore, FsType FS_TYPE>
|
template<typename FileStore, FsType FS_TYPE>
|
||||||
FileStat FileSystemTemplate<FileStore, FS_TYPE>::stat(const char *path) {
|
FileStat FileSystemTemplate<FileStore, FS_TYPE>::stat(const char *path) {
|
||||||
|
auto inode = findInodeOf(path);
|
||||||
FileStat stat;
|
FileStat stat;
|
||||||
|
auto s = m_store->stat(inode);
|
||||||
|
stat.size = s.size;
|
||||||
|
stat.inode = s.inodeId;
|
||||||
|
stat.fileType = s.fileType;
|
||||||
return stat;
|
return stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,17 +294,34 @@ int FileSystemTemplate<FileStore, FS_TYPE>::remove(uint64_t inode) {
|
|||||||
#endif
|
#endif
|
||||||
template<typename FileStore, FsType FS_TYPE>
|
template<typename FileStore, FsType FS_TYPE>
|
||||||
int FileSystemTemplate<FileStore, FS_TYPE>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) {
|
int FileSystemTemplate<FileStore, FS_TYPE>::write(const char *path, void *buffer, uint64_t size, uint8_t fileType) {
|
||||||
int retval = -1;
|
int err = 0;
|
||||||
|
size_t pathLen = ox_strlen(path);
|
||||||
// find the inode for the given path
|
char dirPath[pathLen];
|
||||||
auto inode = findInodeOf(path);
|
char fileName[pathLen];
|
||||||
|
PathIterator pathReader(path, pathLen);
|
||||||
// if inode exists, read the data into buffer
|
err |= pathReader.fileName(fileName, pathLen);
|
||||||
if (inode) {
|
err |= pathReader.dirPath(dirPath, pathLen);
|
||||||
retval = write(inode, buffer, size, fileType);
|
if (err) {
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
uint64_t inode = findInodeOf(path);
|
||||||
|
// find an inode value for the given path
|
||||||
|
if (!inode) {
|
||||||
|
while (!inode) {
|
||||||
|
inode = ox_rand() >> 48;
|
||||||
|
// make sure this does not already exist
|
||||||
|
if (stat(inode).inode) {
|
||||||
|
// that result was unusable, try again
|
||||||
|
inode = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
insertDirectoryEntry(dirPath, fileName, inode);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = write(inode, buffer, size, fileType);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(default:4244)
|
#pragma warning(default:4244)
|
||||||
@@ -325,26 +347,25 @@ uint64_t FileSystemTemplate<FileStore, FS_TYPE>::findInodeOf(const char *path) {
|
|||||||
PathIterator it(path, pathLen);
|
PathIterator it(path, pathLen);
|
||||||
char fileName[pathLen];
|
char fileName[pathLen];
|
||||||
uint64_t inode = INODE_ROOT_DIR;
|
uint64_t inode = INODE_ROOT_DIR;
|
||||||
while (inode) {
|
while (it.hasNext()) {
|
||||||
auto dirStat = m_store->stat(inode);
|
auto dirStat = m_store->stat(inode);
|
||||||
if (dirStat.size >= sizeof(Directory)) {
|
if (dirStat.size >= sizeof(Directory)) {
|
||||||
uint8_t dirBuffer[dirStat.size];
|
uint8_t dirBuffer[dirStat.size];
|
||||||
auto dir = (Directory*) dirBuffer;
|
auto dir = (Directory*) dirBuffer;
|
||||||
if (read(inode, dirBuffer, dirStat.size) == 0) {
|
if (read(inode, dirBuffer, dirStat.size) == 0) {
|
||||||
if (dirStat.fileType == FileType::Directory && it.next(fileName, pathLen) == 0) {
|
if (dirStat.fileType == FileType::Directory && it.next(fileName, pathLen) == 0) {
|
||||||
if (!it.hasNext()) {
|
|
||||||
// no further name components, inode points to the correct file
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
inode = dir->getFileInode(fileName, dirStat.size);
|
inode = dir->getFileInode(fileName, dirStat.size);
|
||||||
} else {
|
} else {
|
||||||
inode = 0; // null out inode and break
|
inode = 0; // null out inode and break
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inode = 0; // null out inode and break
|
inode = 0; // null out inode and break
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inode = 0; // null out inode and break
|
inode = 0; // null out inode and break
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return inode;
|
return inode;
|
||||||
@@ -401,30 +422,51 @@ uint8_t *FileSystemTemplate<FileStore, FS_TYPE>::format(void *buffer, typename F
|
|||||||
#pragma warning(disable:4244)
|
#pragma warning(disable:4244)
|
||||||
#endif
|
#endif
|
||||||
template<typename FileStore, FsType FS_TYPE>
|
template<typename FileStore, FsType FS_TYPE>
|
||||||
int FileSystemTemplate<FileStore, FS_TYPE>::insertDirectoryEntry(uint64_t inode, const char *dirPath, const char *fileName) {
|
int FileSystemTemplate<FileStore, FS_TYPE>::insertDirectoryEntry(const char *dirPath, const char *fileName, uint64_t inode) {
|
||||||
return 0;
|
auto s = stat(dirPath);
|
||||||
|
if (s.inode) {
|
||||||
|
size_t dirBuffSize = s.size + DirectoryEntry::spaceNeeded(fileName) + 100;
|
||||||
|
uint8_t dirBuff[dirBuffSize];
|
||||||
|
int err = read(s.inode, dirBuff, dirBuffSize);
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
auto dir = (Directory*) dirBuff;
|
||||||
|
dir->size += DirectoryEntry::spaceNeeded(fileName);
|
||||||
|
auto entry = (DirectoryEntry*) &dirBuff[s.size];
|
||||||
|
entry->inode = inode;
|
||||||
|
entry->setName(fileName);
|
||||||
|
return write(s.inode, dirBuff, dirBuffSize, FileType::Directory);
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(default:4244)
|
#pragma warning(default:4244)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Directory
|
// Directory
|
||||||
|
|
||||||
template<typename FileStore, FsType FS_TYPE>
|
template<typename FileStore, FsType FS_TYPE>
|
||||||
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::Directory::getFileInode(const char *name, uint64_t buffSize) {
|
uint64_t FileSystemTemplate<FileStore, FS_TYPE>::Directory::getFileInode(const char *name, uint64_t buffSize) {
|
||||||
uint64_t retval = 0;
|
uint64_t inode = 0;
|
||||||
auto current = files();
|
auto current = files();
|
||||||
if (current) {
|
if (current) {
|
||||||
auto end = (DirectoryEntry*) ((uint8_t*) files()) + buffSize;
|
auto end = (DirectoryEntry*) (((uint8_t*) files()) + buffSize);
|
||||||
while (current && ox_strcmp(current->getName(), name) != 0) {
|
while (current && ox_strcmp(current->getName(), name) != 0) {
|
||||||
current = (DirectoryEntry*) ((uint8_t*) current) + current->size();
|
current = (DirectoryEntry*) (((uint8_t*) current) + current->size());
|
||||||
if (current < end) {
|
if (current >= end) {
|
||||||
current = nullptr;
|
current = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
retval = current->inode;
|
if (current) {
|
||||||
|
inode = current->inode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return retval;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef FileSystemTemplate<FileStore16, OxFS_16> FileSystem16;
|
typedef FileSystemTemplate<FileStore16, OxFS_16> FileSystem16;
|
||||||
|
|||||||
@@ -18,6 +18,41 @@ PathIterator::PathIterator(const char *path, size_t maxSize) {
|
|||||||
m_maxSize = maxSize;
|
m_maxSize = maxSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 0 if no error
|
||||||
|
*/
|
||||||
|
int PathIterator::dirPath(char *out, size_t outSize) {
|
||||||
|
int idx = ox_lastIndexOf(m_path, '/', m_maxSize);
|
||||||
|
size_t size = idx + 1;
|
||||||
|
if (idx >= 0 && size < outSize) {
|
||||||
|
ox_memcpy(out, m_path, size);
|
||||||
|
out[size] = 0;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 0 if no error
|
||||||
|
*/
|
||||||
|
int PathIterator::fileName(char *out, size_t outSize) {
|
||||||
|
auto idx = ox_lastIndexOf(m_path, '/', m_maxSize);
|
||||||
|
if (idx >= 0) {
|
||||||
|
idx++; // pass up the preceding /
|
||||||
|
size_t fileNameSize = ox_strlen(&m_path[idx]);
|
||||||
|
if (fileNameSize < outSize) {
|
||||||
|
ox_memcpy(out, &m_path[idx], fileNameSize);
|
||||||
|
out[fileNameSize] = 0;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int PathIterator::next(char *pathOut, size_t pathOutSize) {
|
int PathIterator::next(char *pathOut, size_t pathOutSize) {
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
int retval = 1;
|
int retval = 1;
|
||||||
@@ -46,6 +81,9 @@ bool PathIterator::hasNext() {
|
|||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
|
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) {
|
||||||
size_t start = m_iterator;
|
size_t start = m_iterator;
|
||||||
|
if (m_path[start] == '/') {
|
||||||
|
start++;
|
||||||
|
}
|
||||||
// end is at the next /
|
// end is at the next /
|
||||||
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start);
|
||||||
// correct end if it is invalid, which happens if there is no next /
|
// correct end if it is invalid, which happens if there is no next /
|
||||||
@@ -55,7 +93,6 @@ bool PathIterator::hasNext() {
|
|||||||
size_t end = substr - m_path;
|
size_t end = substr - m_path;
|
||||||
size = end - start;
|
size = end - start;
|
||||||
}
|
}
|
||||||
m_iterator += size;
|
|
||||||
return size > 0;
|
return size > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,16 @@ class PathIterator {
|
|||||||
public:
|
public:
|
||||||
PathIterator(const char *path, size_t maxSize);
|
PathIterator(const char *path, size_t maxSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 0 if no error
|
||||||
|
*/
|
||||||
|
int dirPath(char *pathOut, size_t pathOutSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return 0 if no error
|
||||||
|
*/
|
||||||
|
int fileName(char *out, size_t outSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 0 if no error
|
* @return 0 if no error
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -28,10 +28,14 @@ target_link_libraries(FSTests OxFS OxStd)
|
|||||||
add_test("FileStoreFormat" FileStoreFormat)
|
add_test("FileStoreFormat" FileStoreFormat)
|
||||||
add_test("FileSystemFormat" FileSystemFormat)
|
add_test("FileSystemFormat" FileSystemFormat)
|
||||||
add_test("FileStoreIO" FileStoreIO)
|
add_test("FileStoreIO" FileStoreIO)
|
||||||
add_test("Test\\ PathIterator1" FSTests PathIterator1)
|
add_test("Test\\ PathIterator::next1" FSTests PathIterator::next1)
|
||||||
add_test("Test\\ PathIterator2" FSTests PathIterator2)
|
add_test("Test\\ PathIterator::next2" FSTests PathIterator::next2)
|
||||||
add_test("Test\\ PathIterator3" FSTests PathIterator3)
|
add_test("Test\\ PathIterator::next3" FSTests PathIterator::next3)
|
||||||
add_test("Test\\ PathIterator4" FSTests PathIterator4)
|
add_test("Test\\ PathIterator::next4" FSTests PathIterator::next4)
|
||||||
add_test("Test\\ PathIterator5" FSTests PathIterator5)
|
add_test("Test\\ PathIterator::next5" FSTests PathIterator::next5)
|
||||||
|
|
||||||
add_test("Test\\ FileSystem32::findInodeOf" FSTests FileSystem32::findInodeOf)
|
add_test("Test\\ PathIterator::dirPath" FSTests PathIterator::dirPath)
|
||||||
|
add_test("Test\\ PathIterator::fileName" FSTests PathIterator::fileName)
|
||||||
|
|
||||||
|
add_test("Test\\ FileSystem32::findInodeOf\\ /" FSTests "FileSystem32::findInodeOf /")
|
||||||
|
add_test("Test\\ FileSystem32::write\\(string\\)" FSTests "FileSystem32::write(string)")
|
||||||
|
|||||||
@@ -15,12 +15,11 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace ox::fs;
|
using namespace ox::fs;
|
||||||
using namespace ox::std;
|
|
||||||
|
|
||||||
map<string, int(*)(string)> tests = {
|
map<string, function<int(string)>> tests = {
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"PathIterator1",
|
"PathIterator::next1",
|
||||||
[](string) {
|
[](string) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
string path = "/usr/share/charset.gbag";
|
string path = "/usr/share/charset.gbag";
|
||||||
@@ -35,7 +34,7 @@ map<string, int(*)(string)> tests = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"PathIterator2",
|
"PathIterator::next2",
|
||||||
[](string) {
|
[](string) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
string path = "/usr/share/";
|
string path = "/usr/share/";
|
||||||
@@ -49,7 +48,7 @@ map<string, int(*)(string)> tests = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"PathIterator3",
|
"PathIterator::next3",
|
||||||
[](string) {
|
[](string) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
string path = "/";
|
string path = "/";
|
||||||
@@ -62,7 +61,7 @@ map<string, int(*)(string)> tests = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"PathIterator4",
|
"PathIterator::next4",
|
||||||
[](string) {
|
[](string) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
string path = "usr/share/charset.gbag";
|
string path = "usr/share/charset.gbag";
|
||||||
@@ -77,7 +76,7 @@ map<string, int(*)(string)> tests = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"PathIterator5",
|
"PathIterator::next5",
|
||||||
[](string) {
|
[](string) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
string path = "usr/share/";
|
string path = "usr/share/";
|
||||||
@@ -91,7 +90,33 @@ map<string, int(*)(string)> tests = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"FileSystem32::findInodeOf",
|
"PathIterator::dirPath",
|
||||||
|
[] (string) {
|
||||||
|
int retval = 0;
|
||||||
|
string path = "/usr/share/charset.gbag";
|
||||||
|
PathIterator it(path.c_str(), path.size());
|
||||||
|
const auto buffSize = 1024;
|
||||||
|
char buff[buffSize];
|
||||||
|
assert(buffSize >= path.size());
|
||||||
|
retval |= !(it.dirPath(buff, path.size()) == 0 && ox_strcmp(buff, "/usr/share/") == 0);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PathIterator::fileName",
|
||||||
|
[](string) {
|
||||||
|
int retval = 0;
|
||||||
|
string path = "/usr/share/charset.gbag";
|
||||||
|
PathIterator it(path.c_str(), path.size());
|
||||||
|
const auto buffSize = 1024;
|
||||||
|
char buff[buffSize];
|
||||||
|
assert(buffSize >= path.size());
|
||||||
|
retval |= !(it.fileName(buff, path.size()) == 0 && ox_strcmp(buff, "charset.gbag") == 0);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"FileSystem32::findInodeOf /",
|
||||||
[](string) {
|
[](string) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
const auto size = 1024;
|
const auto size = 1024;
|
||||||
@@ -103,6 +128,29 @@ map<string, int(*)(string)> tests = {
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"FileSystem32::write(string)",
|
||||||
|
[](string) {
|
||||||
|
// this value will likely need to change if anything about the
|
||||||
|
// random number generator changes
|
||||||
|
const auto targetInode = 58542;
|
||||||
|
|
||||||
|
int retval = 0;
|
||||||
|
auto path = "/charset.gbag";
|
||||||
|
auto data = "test";
|
||||||
|
|
||||||
|
const auto size = 1024;
|
||||||
|
uint8_t buff[size];
|
||||||
|
FileSystem32::format(buff, (FileStore32::FsSize_t) size, true);
|
||||||
|
auto fs = (FileSystem32*) createFileSystem(buff, size);
|
||||||
|
|
||||||
|
retval |= fs->write(path, &data, ox_strlen(data));
|
||||||
|
retval |= !(fs->findInodeOf(path) == targetInode);
|
||||||
|
|
||||||
|
delete fs;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 2.8)
|
|||||||
add_library(
|
add_library(
|
||||||
OxStd
|
OxStd
|
||||||
memops.cpp
|
memops.cpp
|
||||||
|
random.cpp
|
||||||
strops.cpp
|
strops.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 - 2017 gtalent2@gmail.com
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.hpp"
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
inline uint64_t rotateLeft(uint64_t i, int shift) {
|
||||||
|
return (i << shift) | (i >> (64 - shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 - 2017 gtalent2@gmail.com
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bitops.hpp"
|
||||||
|
#include "random.hpp"
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
RandomSeed Random::DEFAULT_SEED = {540932923848, 540932540932};
|
||||||
|
|
||||||
|
Random::Random(RandomSeed seed) {
|
||||||
|
m_seed[0] = seed[0];
|
||||||
|
m_seed[1] = seed[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t Random::gen() {
|
||||||
|
auto s0 = m_seed[0];
|
||||||
|
auto s1 = m_seed[1];
|
||||||
|
auto retval = s0 + s1;
|
||||||
|
|
||||||
|
s1 ^= s0;
|
||||||
|
m_seed[0] = ox::rotateLeft(s0, 55) ^ s1 ^ (s1 << 14);
|
||||||
|
m_seed[1] = ox::rotateLeft(s1, 36);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t ox_rand() {
|
||||||
|
static ox::Random rand;
|
||||||
|
return rand.gen();
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 - 2017 gtalent2@gmail.com
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
uint64_t ox_rand();
|
||||||
|
|
||||||
|
namespace ox {
|
||||||
|
|
||||||
|
typedef uint64_t RandomSeed[2];
|
||||||
|
|
||||||
|
class Random {
|
||||||
|
public:
|
||||||
|
static RandomSeed DEFAULT_SEED;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RandomSeed m_seed;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Random(RandomSeed seed = DEFAULT_SEED);
|
||||||
|
|
||||||
|
uint64_t gen();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,7 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "bitops.hpp"
|
||||||
#include "byteswap.hpp"
|
#include "byteswap.hpp"
|
||||||
#include "memops.hpp"
|
#include "memops.hpp"
|
||||||
|
#include "random.hpp"
|
||||||
#include "strops.hpp"
|
#include "strops.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
|
|||||||
@@ -58,6 +58,26 @@ char *ox_strchr(char *str, int character, size_t maxLen) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ox_lastIndexOf(const char *str, int character, int maxLen) {
|
||||||
|
int retval = -1;
|
||||||
|
for (int i = 0; i < maxLen && str[i]; i++) {
|
||||||
|
if (str[i] == character) {
|
||||||
|
retval = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ox_lastIndexOf(char *str, int character, int maxLen) {
|
||||||
|
int retval = -1;
|
||||||
|
for (int i = 0; i < maxLen && str[i]; i++) {
|
||||||
|
if (str[i] == character) {
|
||||||
|
retval = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int ox_atoi(const char *str) {
|
int ox_atoi(const char *str) {
|
||||||
int total = 0;
|
int total = 0;
|
||||||
int multiplier = 1;
|
int multiplier = 1;
|
||||||
|
|||||||
@@ -20,4 +20,8 @@ const char *ox_strchr(const char *str, int character, size_t maxLen = 0xFFFFFFFF
|
|||||||
|
|
||||||
char *ox_strchr(char *str, int character, size_t maxLen = 0xFFFFFFFF);
|
char *ox_strchr(char *str, int character, size_t maxLen = 0xFFFFFFFF);
|
||||||
|
|
||||||
|
int ox_lastIndexOf(const char *str, int character, int maxLen = 0xFFFFFFFF);
|
||||||
|
|
||||||
|
int ox_lastIndexOf(char *str, int character, int maxLen = 0xFFFFFFFF);
|
||||||
|
|
||||||
int ox_atoi(const char *str);
|
int ox_atoi(const char *str);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ add_test("Test\\ ox_strcmp\\ resize\\ !=\\ read" StrOpsTest "resize > read")
|
|||||||
add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest "resize == resize")
|
add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest "resize == resize")
|
||||||
add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest " == ")
|
add_test("Test\\ ox_strcmp\\ resize\\ ==\\ resize" StrOpsTest " == ")
|
||||||
add_test("Test\\ ox_strchr\\ 0" StrOpsTest "ox_strchr 0")
|
add_test("Test\\ ox_strchr\\ 0" StrOpsTest "ox_strchr 0")
|
||||||
|
add_test("Test\\ ox_lastIndexOf\\ aaaa\\ a" StrOpsTest "ox_lastIndexOf aaaa a")
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|||||||
@@ -56,6 +56,16 @@ map<string, function<int()>> tests = {
|
|||||||
return !(ox_strchr(testStr, 0, 4) == &testStr[4]);
|
return !(ox_strchr(testStr, 0, 4) == &testStr[4]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ox_lastIndexOf aaaa a",
|
||||||
|
[]() {
|
||||||
|
int retval = 0;
|
||||||
|
auto testStr = "aaaa";
|
||||||
|
retval |= !(ox_lastIndexOf((char*) testStr, 'a', ox_strlen(testStr)) == 3);
|
||||||
|
retval |= !(ox_lastIndexOf((const char*) testStr, 'a', ox_strlen(testStr)) == 3);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
int main(int argc, const char **args) {
|
int main(int argc, const char **args) {
|
||||||
|
|||||||
Reference in New Issue
Block a user