add array.h/cpp

This commit is contained in:
2025-02-27 16:18:38 +08:00
parent f44aaa81b2
commit d0fd9eb4f0
7 changed files with 410 additions and 0 deletions

8
.env.bat Normal file
View 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%

View File

@@ -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
)

View 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()

View 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);
}

3
code.bat Normal file
View File

@@ -0,0 +1,3 @@
call .env.bat
code.cmd .

318
src/array.cpp Normal file
View 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
View 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