code only
This commit is contained in:
commit
dbc707f23f
10 changed files with 605 additions and 0 deletions
223
lib/stockfish.dart
Normal file
223
lib/stockfish.dart
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
// Using code from https://github.com/ArjanAswal/Stockfish/blob/master/lib/src/stockfish.dart
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:ffi';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'dart:developer' as developer;
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
|
||||||
|
import 'stockfish_bindings_generated.dart';
|
||||||
|
import 'stockfish_state.dart';
|
||||||
|
|
||||||
|
const String _libName = 'stockfish';
|
||||||
|
const String _releaseType = kDebugMode ? 'Debug' : 'Release';
|
||||||
|
|
||||||
|
/// The dynamic library in which the symbols for [StockfishChessEngineBindings] can be found.
|
||||||
|
final DynamicLibrary _dylib = () {
|
||||||
|
if (Platform.isMacOS || Platform.isIOS) {
|
||||||
|
return DynamicLibrary.open('$_libName.framework/$_libName');
|
||||||
|
}
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
return DynamicLibrary.open('lib$_libName.so');
|
||||||
|
}
|
||||||
|
if (Platform.isLinux) {
|
||||||
|
return DynamicLibrary.open(
|
||||||
|
'${File(Platform.resolvedExecutable).parent.parent.path}/plugins/flutter_stockfish_plugin/shared/lib$_libName.so');
|
||||||
|
}
|
||||||
|
if (Platform.isWindows) {
|
||||||
|
return DynamicLibrary.open(
|
||||||
|
'${File(Platform.resolvedExecutable).parent.parent.parent.path}/plugins/flutter_stockfish_plugin/shared/$_releaseType/$_libName.dll');
|
||||||
|
}
|
||||||
|
throw UnsupportedError('Unknown platform: ${Platform.operatingSystem}');
|
||||||
|
}();
|
||||||
|
|
||||||
|
/// The bindings to the native functions in [_dylib].
|
||||||
|
final StockfishChessEngineBindings _bindings =
|
||||||
|
StockfishChessEngineBindings(_dylib);
|
||||||
|
|
||||||
|
/// A wrapper for C++ engine.
|
||||||
|
class Stockfish {
|
||||||
|
final Completer<Stockfish>? completer;
|
||||||
|
|
||||||
|
final _state = _StockfishState();
|
||||||
|
final _stdoutController = StreamController<String>.broadcast();
|
||||||
|
final _mainPort = ReceivePort();
|
||||||
|
final _stdoutPort = ReceivePort();
|
||||||
|
|
||||||
|
late StreamSubscription _mainSubscription;
|
||||||
|
late StreamSubscription _stdoutSubscription;
|
||||||
|
|
||||||
|
Stockfish._({this.completer}) {
|
||||||
|
_mainSubscription =
|
||||||
|
_mainPort.listen((message) => _cleanUp(message is int ? message : 1));
|
||||||
|
_stdoutSubscription = _stdoutPort.listen((message) {
|
||||||
|
if (message is String) {
|
||||||
|
_stdoutController.sink.add(message);
|
||||||
|
} else {
|
||||||
|
developer.log('The stdout isolate sent $message', name: 'Stockfish');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
compute(_spawnIsolates, [_mainPort.sendPort, _stdoutPort.sendPort]).then(
|
||||||
|
(success) {
|
||||||
|
final state = success ? StockfishState.ready : StockfishState.error;
|
||||||
|
_state._setValue(state);
|
||||||
|
if (state == StockfishState.ready) {
|
||||||
|
completer?.complete(this);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error) {
|
||||||
|
developer.log('The init isolate encountered an error $error',
|
||||||
|
name: 'Stockfish');
|
||||||
|
_cleanUp(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stockfish? _instance;
|
||||||
|
|
||||||
|
/// Creates a C++ engine.
|
||||||
|
///
|
||||||
|
/// This may throws a [StateError] if an active instance is being used.
|
||||||
|
/// Owner must [dispose] it before a new instance can be created.
|
||||||
|
factory Stockfish() {
|
||||||
|
if (_instance != null) {
|
||||||
|
throw StateError('Multiple instances are not supported, yet.');
|
||||||
|
}
|
||||||
|
|
||||||
|
_instance = Stockfish._();
|
||||||
|
return _instance!;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The current state of the underlying C++ engine.
|
||||||
|
ValueListenable<StockfishState> get state => _state;
|
||||||
|
|
||||||
|
/// The standard output stream.
|
||||||
|
Stream<String> get stdout => _stdoutController.stream;
|
||||||
|
|
||||||
|
/// The standard input sink.
|
||||||
|
set stdin(String line) {
|
||||||
|
final stateValue = _state.value;
|
||||||
|
if (stateValue != StockfishState.ready) {
|
||||||
|
throw StateError('Stockfish is not ready ($stateValue)');
|
||||||
|
}
|
||||||
|
|
||||||
|
final unicodePointer = '$line\n'.toNativeUtf8();
|
||||||
|
final pointer = unicodePointer.cast<Char>();
|
||||||
|
_bindings.stockfish_stdin_write(pointer);
|
||||||
|
calloc.free(unicodePointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stops the C++ engine.
|
||||||
|
void dispose() {
|
||||||
|
final stateValue = _state.value;
|
||||||
|
if (stateValue == StockfishState.ready) {
|
||||||
|
stdin = 'quit';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _cleanUp(int exitCode) {
|
||||||
|
_stdoutController.close();
|
||||||
|
|
||||||
|
_mainSubscription.cancel();
|
||||||
|
_stdoutSubscription.cancel();
|
||||||
|
|
||||||
|
_state._setValue(
|
||||||
|
exitCode == 0 ? StockfishState.disposed : StockfishState.error);
|
||||||
|
|
||||||
|
_instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a C++ engine asynchronously.
|
||||||
|
///
|
||||||
|
/// This method is different from the factory method [Stockfish] that
|
||||||
|
/// it will wait for the engine to be ready before returning the instance.
|
||||||
|
Future<Stockfish> stockfishAsync() {
|
||||||
|
if (Stockfish._instance != null) {
|
||||||
|
return Future.error(StateError('Only one instance can be used at a time'));
|
||||||
|
}
|
||||||
|
|
||||||
|
final completer = Completer<Stockfish>();
|
||||||
|
Stockfish._instance = Stockfish._(completer: completer);
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _StockfishState extends ChangeNotifier
|
||||||
|
implements ValueListenable<StockfishState> {
|
||||||
|
StockfishState _value = StockfishState.starting;
|
||||||
|
|
||||||
|
@override
|
||||||
|
StockfishState get value => _value;
|
||||||
|
|
||||||
|
_setValue(StockfishState v) {
|
||||||
|
if (v == _value) return;
|
||||||
|
_value = v;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _isolateMain(SendPort mainPort) {
|
||||||
|
final exitCode = _bindings.stockfish_main();
|
||||||
|
mainPort.send(exitCode);
|
||||||
|
|
||||||
|
developer.log('nativeMain returns $exitCode', name: 'Stockfish');
|
||||||
|
print("stoped");
|
||||||
|
}
|
||||||
|
|
||||||
|
void _isolateStdout(SendPort stdoutPort) {
|
||||||
|
String previous = '';
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
final pointer = _bindings.stockfish_stdout_read();
|
||||||
|
|
||||||
|
if (pointer.address == 0) {
|
||||||
|
developer.log('nativeStdoutRead returns NULL', name: 'Stockfish');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uint8List newContentCharList;
|
||||||
|
|
||||||
|
final newContentLength = pointer.cast<Utf8>().length;
|
||||||
|
newContentCharList = Uint8List.view(
|
||||||
|
pointer.cast<Uint8>().asTypedList(newContentLength).buffer,
|
||||||
|
0,
|
||||||
|
newContentLength);
|
||||||
|
|
||||||
|
final newContent = utf8.decode(newContentCharList);
|
||||||
|
|
||||||
|
final data = previous + newContent;
|
||||||
|
final lines = data.split('\n');
|
||||||
|
previous = lines.removeLast();
|
||||||
|
for (final line in lines) {
|
||||||
|
stdoutPort.send(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> _spawnIsolates(List<SendPort> mainAndStdout) async {
|
||||||
|
final initResult = _bindings.stockfish_init();
|
||||||
|
if (initResult != 0) {
|
||||||
|
developer.log('initResult=$initResult', name: 'Stockfish');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Isolate.spawn(_isolateStdout, mainAndStdout[1]);
|
||||||
|
} catch (error) {
|
||||||
|
developer.log('Failed to spawn stdout isolate: $error', name: 'Stockfish');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Isolate.spawn(_isolateMain, mainAndStdout[0]);
|
||||||
|
} catch (error) {
|
||||||
|
developer.log('Failed to spawn main isolate: $error', name: 'Stockfish');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
71
lib/stockfish_bindings_generated.dart
Normal file
71
lib/stockfish_bindings_generated.dart
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// ignore_for_file: always_specify_types
|
||||||
|
// ignore_for_file: camel_case_types
|
||||||
|
// ignore_for_file: non_constant_identifier_names
|
||||||
|
|
||||||
|
// AUTO GENERATED FILE, DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// Generated by `package:ffigen`.
|
||||||
|
import 'dart:ffi' as ffi;
|
||||||
|
|
||||||
|
/// Bindings for `src/stockfish.h`.
|
||||||
|
///
|
||||||
|
/// Regenerate bindings with `dart run ffigen --config ffigen.yaml`.
|
||||||
|
///
|
||||||
|
class StockfishChessEngineBindings {
|
||||||
|
/// Holds the symbol lookup function.
|
||||||
|
final ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||||
|
_lookup;
|
||||||
|
|
||||||
|
/// The symbols are looked up in [dynamicLibrary].
|
||||||
|
StockfishChessEngineBindings(ffi.DynamicLibrary dynamicLibrary)
|
||||||
|
: _lookup = dynamicLibrary.lookup;
|
||||||
|
|
||||||
|
/// The symbols are looked up with [lookup].
|
||||||
|
StockfishChessEngineBindings.fromLookup(
|
||||||
|
ffi.Pointer<T> Function<T extends ffi.NativeType>(String symbolName)
|
||||||
|
lookup)
|
||||||
|
: _lookup = lookup;
|
||||||
|
|
||||||
|
int stockfish_init() {
|
||||||
|
return _stockfish_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _stockfish_initPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Int Function()>>('stockfish_init');
|
||||||
|
late final _stockfish_init = _stockfish_initPtr.asFunction<int Function()>();
|
||||||
|
|
||||||
|
int stockfish_main() {
|
||||||
|
return _stockfish_main();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _stockfish_mainPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Int Function()>>('stockfish_main');
|
||||||
|
late final _stockfish_main = _stockfish_mainPtr.asFunction<int Function()>();
|
||||||
|
|
||||||
|
int stockfish_stdin_write(
|
||||||
|
ffi.Pointer<ffi.Char> data,
|
||||||
|
) {
|
||||||
|
return _stockfish_stdin_write(
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _stockfish_stdin_writePtr =
|
||||||
|
_lookup<ffi.NativeFunction<ssize_t Function(ffi.Pointer<ffi.Char>)>>(
|
||||||
|
'stockfish_stdin_write');
|
||||||
|
late final _stockfish_stdin_write = _stockfish_stdin_writePtr
|
||||||
|
.asFunction<int Function(ffi.Pointer<ffi.Char>)>();
|
||||||
|
|
||||||
|
ffi.Pointer<ffi.Char> stockfish_stdout_read() {
|
||||||
|
return _stockfish_stdout_read();
|
||||||
|
}
|
||||||
|
|
||||||
|
late final _stockfish_stdout_readPtr =
|
||||||
|
_lookup<ffi.NativeFunction<ffi.Pointer<ffi.Char> Function()>>(
|
||||||
|
'stockfish_stdout_read');
|
||||||
|
late final _stockfish_stdout_read =
|
||||||
|
_stockfish_stdout_readPtr.asFunction<ffi.Pointer<ffi.Char> Function()>();
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef ssize_t = __ssize_t;
|
||||||
|
typedef __ssize_t = ffi.Long;
|
16
lib/stockfish_state.dart
Normal file
16
lib/stockfish_state.dart
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// Taken from https://github.com/ArjanAswal/Stockfish/blob/master/lib/src/stockfish_state.dart
|
||||||
|
|
||||||
|
/// C++ engine state.
|
||||||
|
enum StockfishState {
|
||||||
|
/// Engine has been stopped.
|
||||||
|
disposed,
|
||||||
|
|
||||||
|
/// An error occured (engine could not start).
|
||||||
|
error,
|
||||||
|
|
||||||
|
/// Engine is running.
|
||||||
|
ready,
|
||||||
|
|
||||||
|
/// Engine is starting.
|
||||||
|
starting,
|
||||||
|
}
|
22
linux/CMakeLists.txt
Normal file
22
linux/CMakeLists.txt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# The Flutter tooling requires that developers have CMake 3.22 or later
|
||||||
|
# installed. You should not increase this version, as doing so will cause
|
||||||
|
# the plugin to fail to compile for some customers of the plugin.
|
||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
# Project-level configuration.
|
||||||
|
set(PROJECT_NAME "stockfish")
|
||||||
|
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Invoke the build for native code shared with the other target platforms.
|
||||||
|
# This can be changed to accomodate different builds.
|
||||||
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared")
|
||||||
|
|
||||||
|
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||||
|
# This list could contain prebuilt libraries, or libraries created by an
|
||||||
|
# external build triggered from this build file.
|
||||||
|
set(stockfish_bundled_libraries
|
||||||
|
# Defined in ../src/CMakeLists.txt.
|
||||||
|
# This can be changed to accomodate different builds.
|
||||||
|
$<TARGET_FILE:stockfish>
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
41
src/CMakeLists.txt
Normal file
41
src/CMakeLists.txt
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# The Flutter tooling requires that developers have CMake 3.18 or later
|
||||||
|
# installed. You should not increase this version, as doing so will cause
|
||||||
|
# the plugin to fail to compile for some customers of the plugin.
|
||||||
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
|
project(stockfish VERSION 0.0.1 LANGUAGES CXX)
|
||||||
|
file(GLOB_RECURSE cppPaths "Stockfish/src/*.cpp")
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(NNUE_NAME nn-0000000000a0.nnue)
|
||||||
|
|
||||||
|
add_library(stockfish SHARED
|
||||||
|
"stockfish.cpp"
|
||||||
|
"stream_fix.cpp"
|
||||||
|
${cppPaths}
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(stockfish PROPERTIES
|
||||||
|
PUBLIC_HEADER stockfish.h
|
||||||
|
OUTPUT_NAME "stockfish"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
add_definitions(/FI"stream_fix.h")
|
||||||
|
else()
|
||||||
|
add_definitions(-include stream_fix.h)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(stockfish PUBLIC DART_SHARED_LIB)
|
||||||
|
|
||||||
|
target_include_directories(stockfish
|
||||||
|
PUBLIC
|
||||||
|
"./"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
file(DOWNLOAD https://tests.stockfishchess.org/api/nn/${NNUE_NAME} ${CMAKE_BINARY_DIR}/runner/Debug/${NNUE_NAME})
|
||||||
|
file(COPY ${CMAKE_BINARY_DIR}/runner/Debug/${NNUE_NAME} DESTINATION ${CMAKE_BINARY_DIR}/runner/Release)
|
||||||
|
else ()
|
||||||
|
file(DOWNLOAD https://tests.stockfishchess.org/api/nn/${NNUE_NAME} ${CMAKE_BINARY_DIR}/${NNUE_NAME})
|
||||||
|
endif ()
|
66
src/stockfish.cpp
Normal file
66
src/stockfish.cpp
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <io.h>
|
||||||
|
#define STDIN_FILENO 0
|
||||||
|
#define STDOUT_FILENO 1
|
||||||
|
#define STDERR_FILENO 2
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define ssize_t __int64
|
||||||
|
#else
|
||||||
|
#define ssize_t long
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
#include "stockfish.h"
|
||||||
|
|
||||||
|
const char *QUITOK = "quitok\n";
|
||||||
|
|
||||||
|
int main(int, char **);
|
||||||
|
|
||||||
|
int stockfish_init() {
|
||||||
|
std::cout << "Init Stockfish: Nothing todo!";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int stockfish_main() {
|
||||||
|
int argc = 1;
|
||||||
|
char *argv[] = {(char *)""};
|
||||||
|
int exitCode = main(argc, argv);
|
||||||
|
|
||||||
|
fakeout << QUITOK << "\n";
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
fakeout.close();
|
||||||
|
fakein.close();
|
||||||
|
|
||||||
|
return exitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t stockfish_stdin_write(char *data) {
|
||||||
|
std::string val(data);
|
||||||
|
fakein << val << fakeendl;
|
||||||
|
return val.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string data;
|
||||||
|
char buffer[BUFFER_SIZE + 1];
|
||||||
|
|
||||||
|
char *stockfish_stdout_read() {
|
||||||
|
if (getline(fakeout, data)) {
|
||||||
|
size_t len = data.length();
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < len && i < BUFFER_SIZE; i++) {
|
||||||
|
buffer[i] = data[i];
|
||||||
|
}
|
||||||
|
buffer[i] = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
46
src/stockfish.h
Normal file
46
src/stockfish.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
//#define _ffigen
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <BaseTsd.h>
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define FFI_PLUGIN_EXPORT __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define FFI_PLUGIN_EXPORT __attribute__((visibility("default"))) __attribute__((used))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Initialisation of Stockfish.
|
||||||
|
#ifndef _ffigen
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
FFI_PLUGIN_EXPORT int stockfish_init();
|
||||||
|
|
||||||
|
// Stockfish main loop.
|
||||||
|
#ifndef _ffigen
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
FFI_PLUGIN_EXPORT int stockfish_main();
|
||||||
|
|
||||||
|
// Writing to Stockfish STDIN.
|
||||||
|
#ifndef _ffigen
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
FFI_PLUGIN_EXPORT ssize_t stockfish_stdin_write(char *data);
|
||||||
|
|
||||||
|
// Reading Stockfish STDOUT
|
||||||
|
#ifndef _ffigen
|
||||||
|
extern "C"
|
||||||
|
#endif
|
||||||
|
FFI_PLUGIN_EXPORT char * stockfish_stdout_read();
|
31
src/stream_fix.cpp
Normal file
31
src/stream_fix.cpp
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#include "stream_fix.h"
|
||||||
|
|
||||||
|
bool FakeStream::try_get_line(std::string& val) {
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_guard);
|
||||||
|
if (string_queue.empty() || closed) return false;
|
||||||
|
val = string_queue.front();
|
||||||
|
string_queue.pop();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeStream::close() {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_guard);
|
||||||
|
closed = true;
|
||||||
|
mutex_signal.notify_one();
|
||||||
|
}
|
||||||
|
bool FakeStream::is_closed() { return closed; }
|
||||||
|
|
||||||
|
std::streambuf* FakeStream::rdbuf() { return nullptr; }
|
||||||
|
|
||||||
|
std::streambuf* FakeStream::rdbuf(std::streambuf* __sb) { return nullptr; }
|
||||||
|
|
||||||
|
bool std::getline(FakeStream& is, std::string& str) {
|
||||||
|
if (is.is_closed()) return false;
|
||||||
|
is >> str;
|
||||||
|
if (is.is_closed()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeStream fakeout;
|
||||||
|
FakeStream fakein;
|
||||||
|
std::string fakeendl("\n");
|
66
src/stream_fix.h
Normal file
66
src/stream_fix.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#ifndef _STREAM_FIX_H_
|
||||||
|
#define _STREAM_FIX_H_
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline std::string stringify(const T& input) {
|
||||||
|
std::ostringstream output; // from www .ja va 2s . com
|
||||||
|
output << input;
|
||||||
|
return output.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FakeStream {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
FakeStream& operator<<(const T& val) {
|
||||||
|
if (closed) return *this;
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_guard);
|
||||||
|
string_queue.push(stringify(val));
|
||||||
|
mutex_signal.notify_one();
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
template <typename T>
|
||||||
|
FakeStream& operator>>(T& val) {
|
||||||
|
if (closed) return *this;
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_guard);
|
||||||
|
mutex_signal.wait(lock,
|
||||||
|
[this] { return !string_queue.empty() || closed; });
|
||||||
|
if (closed) return *this;
|
||||||
|
val = string_queue.front();
|
||||||
|
string_queue.pop();
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool try_get_line(std::string& val);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
bool is_closed();
|
||||||
|
|
||||||
|
std::streambuf* rdbuf();
|
||||||
|
std::streambuf* rdbuf(std::streambuf* __sb);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool closed = false;
|
||||||
|
std::queue<std::string> string_queue;
|
||||||
|
std::string line;
|
||||||
|
std::mutex mutex_guard;
|
||||||
|
std::condition_variable mutex_signal;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
bool getline(FakeStream& is, std::string& str);
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
// #define endl fakeendl
|
||||||
|
// #define cout fakeout
|
||||||
|
// #define cin fakein
|
||||||
|
|
||||||
|
extern FakeStream fakeout;
|
||||||
|
extern FakeStream fakein;
|
||||||
|
extern std::string fakeendl;
|
||||||
|
|
||||||
|
#endif
|
23
windows/CMakeLists.txt
Normal file
23
windows/CMakeLists.txt
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# The Flutter tooling requires that developers have a version of Visual Studio
|
||||||
|
# installed that includes CMake 3.22 or later. You should not increase this
|
||||||
|
# version, as doing so will cause the plugin to fail to compile for some
|
||||||
|
# customers of the plugin.
|
||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
# Project-level configuration.
|
||||||
|
set(PROJECT_NAME "stockfish")
|
||||||
|
project(${PROJECT_NAME} LANGUAGES CXX)
|
||||||
|
|
||||||
|
# Invoke the build for native code shared with the other target platforms.
|
||||||
|
# This can be changed to accomodate different builds.
|
||||||
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../src" "${CMAKE_CURRENT_BINARY_DIR}/shared")
|
||||||
|
|
||||||
|
# List of absolute paths to libraries that should be bundled with the plugin.
|
||||||
|
# This list could contain prebuilt libraries, or libraries created by an
|
||||||
|
# external build triggered from this build file.
|
||||||
|
set(stockfish_bundled_libraries
|
||||||
|
# Defined in ../src/CMakeLists.txt.
|
||||||
|
# This can be changed to accomodate different builds.
|
||||||
|
$<TARGET_FILE:stockfish>
|
||||||
|
PARENT_SCOPE
|
||||||
|
)
|
Loading…
Reference in a new issue