add array.h/cpp
This commit is contained in:
8
.env.bat
Normal file
8
.env.bat
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
@REM set MSYS_PATH=C:\msys64\usr\bin
|
||||||
|
set MSYS_PATH=%USERPROFILE%\scoop\apps\msys2\current
|
||||||
|
|
||||||
|
@REM gcc
|
||||||
|
@REM set PATH=%MSYS_PATH%\mingw64\bin;%MSYS_PATH%\usr\bin;%PATH%
|
||||||
|
|
||||||
|
@REM clang
|
||||||
|
set PATH=%MSYS_PATH%\clang64\bin;%MSYS_PATH%\usr\bin;%PATH%
|
||||||
@@ -1,9 +1,42 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.11) # FetchContent
|
||||||
|
|
||||||
project(keycode)
|
project(keycode)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
include("cmake/Check-from_chars.cmake")
|
||||||
|
|
||||||
|
set (LIBS fmt)
|
||||||
|
|
||||||
|
if (NOT DEFINED OPTCON_LOCAL_BUILD)
|
||||||
|
FetchContent_Declare(
|
||||||
|
fmt
|
||||||
|
GIT_REPOSITORY https://github.com/fmtlib/fmt
|
||||||
|
GIT_TAG 123913715afeb8a437e6388b4473fcc4753e1c9a # 11.1.4
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(fmt)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT FROM_CHARS_WORKS)
|
||||||
|
FetchContent_Declare(
|
||||||
|
fast_float
|
||||||
|
GIT_REPOSITORY https://github.com/fastfloat/fast_float
|
||||||
|
GIT_TAG 77cc847c842c49e7e3477c1e95da2b6540166d66 # 8.0.0
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(fast_float)
|
||||||
|
|
||||||
|
list(APPEND LIBS fast_float)
|
||||||
|
add_definitions(-DUSE_FAST_FLOAT)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(keycode STATIC
|
add_library(keycode STATIC
|
||||||
|
src/array.cpp
|
||||||
src/keycode.c
|
src/keycode.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(keycode ${LIBS})
|
||||||
|
|
||||||
target_include_directories(keycode
|
target_include_directories(keycode
|
||||||
PUBLIC src
|
PUBLIC src
|
||||||
)
|
)
|
||||||
|
|||||||
7
cmake/check-from_chars.cmake
Normal file
7
cmake/check-from_chars.cmake
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
message(STATUS "Checking that std::from_chars for floats is supported by the C++ library")
|
||||||
|
try_compile(FROM_CHARS_WORKS "${CMAKE_BINARY_DIR}" "${CMAKE_CURRENT_LIST_DIR}/check-from_chars.cpp")
|
||||||
|
if(FROM_CHARS_WORKS)
|
||||||
|
message(STATUS "Checking that std::from_chars for floats is supported by the C++ library - yes")
|
||||||
|
else()
|
||||||
|
message(STATUS "Checking that std::from_chars for floats is supported by the C++ library - NO")
|
||||||
|
endif()
|
||||||
8
cmake/check-from_chars.cpp
Normal file
8
cmake/check-from_chars.cpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <charconv>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
const char str[] = "1.2345e3";
|
||||||
|
float num;
|
||||||
|
std::from_chars(str, str + sizeof str - 1, num);
|
||||||
|
}
|
||||||
318
src/array.cpp
Normal file
318
src/array.cpp
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
#include <algorithm>
|
||||||
|
#include <fmt/color.h>
|
||||||
|
#include <keycode.h>
|
||||||
|
#include <limits>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#if USE_FAST_FLOAT
|
||||||
|
#include <fast_float/fast_float.h>
|
||||||
|
using fast_float::from_chars;
|
||||||
|
using fast_float::from_chars_result;
|
||||||
|
#else
|
||||||
|
#include <charconv>
|
||||||
|
using std::from_chars;
|
||||||
|
using std::from_chars_result;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
|
constexpr int PRINT_OFFSET = 30;
|
||||||
|
|
||||||
|
inline void
|
||||||
|
putchar_n(int c, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
putchar(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
goback(int count)
|
||||||
|
{
|
||||||
|
putchar_n('\b', count);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
goback(std::string_view str)
|
||||||
|
{
|
||||||
|
goback(str.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::tuple<T, bool>
|
||||||
|
from_string(std::string_view str)
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
bool ok = false;
|
||||||
|
auto start = str.data();
|
||||||
|
auto end = str.data() + str.size();
|
||||||
|
auto [ptr, ec] = from_chars(start, end, value);
|
||||||
|
|
||||||
|
if (ec == std::errc() && ptr == end) {
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { value, ok };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::string
|
||||||
|
format_value(T value)
|
||||||
|
{
|
||||||
|
return fmt::format("{}", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
std::string
|
||||||
|
format_value<double>(double value)
|
||||||
|
{
|
||||||
|
return fmt::format("{:.7g}", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr std::string_view
|
||||||
|
allowed_symbols();
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr std::string_view
|
||||||
|
allowed_symbols<long>()
|
||||||
|
{
|
||||||
|
return "01234567890+-";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr std::string_view
|
||||||
|
allowed_symbols<double>()
|
||||||
|
{
|
||||||
|
return "01234567890+-.e";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool
|
||||||
|
is_allowed(int c)
|
||||||
|
{
|
||||||
|
auto as = allowed_symbols<T>();
|
||||||
|
return isprint(c) && (as.find((char)c) != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
print_value(T value, T min, T max)
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
str = fmt::format(" {}", format_value(value));
|
||||||
|
str = fmt::format("{:.>{}}", str, PRINT_OFFSET);
|
||||||
|
str = fmt::format("{} [{:g}, {:g}]", str, (double)min, (double)max);
|
||||||
|
|
||||||
|
fmt::print(fg(fmt::color::gray), str);
|
||||||
|
goback(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
print_value(T value)
|
||||||
|
{
|
||||||
|
T min = std::numeric_limits<T>::lowest();
|
||||||
|
T max = std::numeric_limits<T>::max();
|
||||||
|
|
||||||
|
print_value(value, min, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
edit_value(T& value, T min, T max, int exist_key = -1)
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
if (is_allowed<T>(exist_key)) {
|
||||||
|
str += exist_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
while (true) {
|
||||||
|
print_value(value, min, max);
|
||||||
|
|
||||||
|
auto [new_value, ok] = from_string<T>(str);
|
||||||
|
if (ok) {
|
||||||
|
if (new_value != std::clamp(new_value, min, max)) {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
fmt::print("{} ", str);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fmt::print(fg(fmt::color::red), "{} ", str);
|
||||||
|
}
|
||||||
|
goback(1);
|
||||||
|
|
||||||
|
int key = keycode();
|
||||||
|
goback(str);
|
||||||
|
|
||||||
|
if (key == KEY_ESC) {
|
||||||
|
print_value(value, min, max);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (key == KEY_ENTER && ok) {
|
||||||
|
value = new_value;
|
||||||
|
str.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (key == KEY_BS && !str.empty()) {
|
||||||
|
str.pop_back();
|
||||||
|
}
|
||||||
|
else if (is_allowed<T>(key)) {
|
||||||
|
str += key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
edit_value(T& old_value, int exist_key = -1)
|
||||||
|
{
|
||||||
|
T min = std::numeric_limits<T>::lowest();
|
||||||
|
T max = std::numeric_limits<T>::max();
|
||||||
|
|
||||||
|
edit_value(old_value, min, max, exist_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using limit = std::variant<T, T*>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
T
|
||||||
|
limit_get(limit<T> l, int index)
|
||||||
|
{
|
||||||
|
if (l.index() == 0) {
|
||||||
|
return std::get<T>(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::get<T*>(l)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
edit_array(
|
||||||
|
T* array,
|
||||||
|
int len,
|
||||||
|
limit<T> _min,
|
||||||
|
limit<T> _max,
|
||||||
|
bool zero_based_indexing = true)
|
||||||
|
{
|
||||||
|
auto min = [_min](int index) -> T {
|
||||||
|
return limit_get(_min, index);
|
||||||
|
};
|
||||||
|
auto max = [_max](int index) -> T {
|
||||||
|
return limit_get(_max, index);
|
||||||
|
};
|
||||||
|
|
||||||
|
const int start_index = zero_based_indexing ? 0 : 1;
|
||||||
|
const int end_index = zero_based_indexing ? (len - 1) : len;
|
||||||
|
int index = start_index;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (index > end_index) {
|
||||||
|
index = start_index;
|
||||||
|
}
|
||||||
|
else if (index < start_index) {
|
||||||
|
index = end_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto s = fmt::format("[{:4}] ", index);
|
||||||
|
fmt::print("{}", s);
|
||||||
|
|
||||||
|
print_value(array[index], min(index), max(index));
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int key = keycode();
|
||||||
|
if (key == KEY_ESC) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (key == KEY_LEFT) {
|
||||||
|
--index;
|
||||||
|
goback(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (key == KEY_RIGHT) {
|
||||||
|
++index;
|
||||||
|
goback(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (is_allowed<T>(key)) {
|
||||||
|
edit_value(array[index], min(index), max(index), key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
edit_array(T* array, int len, bool zero_based_indexing = true)
|
||||||
|
{
|
||||||
|
T min = std::numeric_limits<T>::lowest();
|
||||||
|
T max = std::numeric_limits<T>::max();
|
||||||
|
|
||||||
|
edit_array(array, len, { min }, { max }, zero_based_indexing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================================================================
|
||||||
|
// Gornov API
|
||||||
|
// ==============================================================================
|
||||||
|
|
||||||
|
void
|
||||||
|
taklong(long* value)
|
||||||
|
{
|
||||||
|
printf(" ");
|
||||||
|
edit_value(*value);
|
||||||
|
printf("\b");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
takdouble(double* value)
|
||||||
|
{
|
||||||
|
printf(" ");
|
||||||
|
edit_value(*value);
|
||||||
|
printf("\b");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtaklong(long* value, long min, long max)
|
||||||
|
{
|
||||||
|
printf(" ");
|
||||||
|
edit_value(*value, min, max);
|
||||||
|
printf("\b");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rtakdouble(double* value, double min, double max)
|
||||||
|
{
|
||||||
|
printf(" ");
|
||||||
|
edit_value(*value, min, max);
|
||||||
|
printf("\b");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
takari(long* array, long len)
|
||||||
|
{
|
||||||
|
edit_array(array, len, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
takarr(double* array, long len)
|
||||||
|
{
|
||||||
|
edit_array(array, len, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
takarr_lg(double* array, long len, double* min, double* max)
|
||||||
|
{
|
||||||
|
edit_array(array, len, { min }, { max }, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
takari_lg(long* array, long len, long* min, long* max)
|
||||||
|
{
|
||||||
|
edit_array(array, len, { min }, { max }, false);
|
||||||
|
}
|
||||||
33
src/array.h
Normal file
33
src/array.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
taklong(long*);
|
||||||
|
|
||||||
|
void
|
||||||
|
takdouble(double*);
|
||||||
|
|
||||||
|
void
|
||||||
|
takarr(double*, long);
|
||||||
|
|
||||||
|
void
|
||||||
|
takarr_lg(double*, long, double*, double*);
|
||||||
|
|
||||||
|
void
|
||||||
|
takari(long*, long);
|
||||||
|
|
||||||
|
void
|
||||||
|
takari_lg(long*, long, long*, long*);
|
||||||
|
|
||||||
|
void
|
||||||
|
rtaklong(long* i, long imin, long imax);
|
||||||
|
|
||||||
|
void
|
||||||
|
rtakdouble(double* d, double dmin, double dmax);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user