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)
|
||||
|
||||
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
|
||||
src/array.cpp
|
||||
src/keycode.c
|
||||
)
|
||||
|
||||
target_link_libraries(keycode ${LIBS})
|
||||
|
||||
target_include_directories(keycode
|
||||
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