diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2784a6154..67793e0c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -62,7 +62,7 @@ jobs: xcode: '15.0' cc: 'clang' cxx: 'clang++' - buildType: [ Release, Debug ] + buildType: [ Release, Debug, RelWithDebInfo ] name: "${{ matrix.config.name }}-${{matrix.buildType}}" runs-on: ${{ matrix.config.image }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 16422d2ae..154d73136 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,10 +190,13 @@ set(dxFeedGraalCxxApi_Exceptions_Sources ) set(dxFeedGraalCxxApi_Isolated_Sources + src/isolated/api/IsolatedDXFeed.cpp src/isolated/api/IsolatedDXEndpoint.cpp + src/isolated/api/IsolatedDXFeedSubscription.cpp src/isolated/api/IsolatedDXPublisher.cpp src/isolated/api/IsolatedDXPublisherObservableSubscription.cpp src/isolated/api/osub/IsolatedObservableSubscriptionChangeListener.cpp + src/isolated/promise/IsolatedPromise.cpp src/isolated/internal/IsolatedString.cpp src/isolated/internal/IsolatedTimeFormat.cpp ) @@ -227,6 +230,10 @@ set(dxFeedGraalCxxApi_OnDemand_Sources src/ondemand/OnDemandService.cpp ) +set(dxFeedGraalCxxApi_Promise_Sources + src/promise/Promise.cpp +) + set(dxFeedGraalCxxApi_Symbols_Sources src/symbols/StringSymbol.cpp src/symbols/SymbolWrapper.cpp @@ -314,6 +321,7 @@ set(dxFeedGraalCxxApi_Sources ${dxFeedGraalCxxApi_ApiOsub_Sources} ${dxFeedGraalCxxApi_Ipf_Sources} ${dxFeedGraalCxxApi_OnDemand_Sources} + ${dxFeedGraalCxxApi_Promise_Sources} ${dxFeedGraalCxxApi_Symbols_Sources} ${dxFeedGraalCxxApi_System_Sources} ${dxFeedGraalCxxApi_Event_Sources} @@ -372,6 +380,14 @@ set(DXFCXX_GCC_LIKE_LINK_OPTIONS "-fPIC") #A workaround to fix 'relocation truncated to fit: IMAGE_REL_AMD64_SECREL' error (MinGW + Debug) set(DXFCXX_MINGW_DEBUG_LINK_OPTIONS "-Wl,--disable-dynamicbase,--disable-high-entropy-va,--default-image-base-low") +# https://developercommunity.visualstudio.com/t/Invalid-code-generation-in-release-1940/10678572?sort=newest&viewtype=all +# https://github.com/microsoft/STL/wiki/Changelog#vs-2022-1710 +# https://github.com/actions/runner-images/issues/10004 +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + target_compile_definitions(${PROJECT_NAME} PUBLIC _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) + target_compile_definitions(${PROJECT_NAME}_static PUBLIC _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) +endif () + target_compile_options(${PROJECT_NAME} PUBLIC $<$:${DXFCXX_MSVC_COMPILE_OPTIONS}> @@ -468,6 +484,7 @@ if (DXFCXX_BUILD_SAMPLES) add_subdirectory(samples/cpp/PrintQuoteEvents) add_subdirectory(samples/cpp/PublishProfiles) add_subdirectory(samples/cpp/DxFeedSample) + add_subdirectory(samples/cpp/FetchDailyCandles) add_subdirectory(samples/cpp/WriteTapeFile) add_subdirectory(samples/cpp/ConvertTapeFile) add_subdirectory(samples/cpp/DxFeedFileParser) diff --git a/README.md b/README.md index 7e65d43ad..e8e09ffd1 100644 --- a/README.md +++ b/README.md @@ -355,6 +355,8 @@ versions): is a simple demonstration of how to get various scheduling information for instruments - [x] [OnDemandSample](https://github.com/dxFeed/dxfeed-graal-cxx-api/blob/main/samples/cpp/OnDemandSample/src/main.cpp) a sample that demonstrates how to use the dxFeed on-demand history data replay service API +- [x] [FetchDailyCandles](https://github.com/dxFeed/dxfeed-graal-cxx-api/blob/main/samples/cpp/FetchDailyCandles/src/main.cpp) + a sample that demonstrates how to fetch last 20 days of candles for a specified symbol and print them. ## Current State diff --git a/include/dxfeed_graal_cpp_api/api.hpp b/include/dxfeed_graal_cpp_api/api.hpp index f38bc16a9..26a9222fb 100644 --- a/include/dxfeed_graal_cpp_api/api.hpp +++ b/include/dxfeed_graal_cpp_api/api.hpp @@ -52,14 +52,19 @@ DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251 4996) #include "exceptions/JavaException.hpp" #include "exceptions/GraalException.hpp" +#include "isolated/api/IsolatedDXFeed.hpp" #include "isolated/api/IsolatedDXEndpoint.hpp" +#include "isolated/api/IsolatedDXFeedSubscription.hpp" #include "isolated/api/IsolatedDXPublisher.hpp" #include "isolated/api/IsolatedDXPublisherObservableSubscription.hpp" #include "isolated/api/osub/IsolatedObservableSubscriptionChangeListener.hpp" +#include "isolated/promise/IsolatedPromise.hpp" #include "isolated/internal/IsolatedString.hpp" #include "isolated/internal/IsolatedTimeFormat.hpp" #include "isolated/internal/IsolatedTools.hpp" #include "ondemand/OnDemandService.hpp" +#include "promise/Promise.hpp" + DXFCXX_DISABLE_MSC_WARNINGS_POP() \ No newline at end of file diff --git a/include/dxfeed_graal_cpp_api/api/DXFeed.hpp b/include/dxfeed_graal_cpp_api/api/DXFeed.hpp index c264d79ea..acce0eae5 100644 --- a/include/dxfeed_graal_cpp_api/api/DXFeed.hpp +++ b/include/dxfeed_graal_cpp_api/api/DXFeed.hpp @@ -12,6 +12,7 @@ DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) #include "../internal/Handler.hpp" #include "../internal/Isolate.hpp" #include "../internal/JavaObjectHandle.hpp" +#include "../promise/Promise.hpp" #include "DXFeedSubscription.hpp" @@ -124,6 +125,9 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { JavaObjectHandle handle_; static std::shared_ptr create(void *feedHandle); + void *getTimeSeriesPromiseImpl(const EventTypeEnum &eventType, const SymbolWrapper &symbol, std::int64_t fromTime, + std::int64_t toTime) const; + protected: DXFeed() noexcept : handle_{} { if constexpr (Debugger::isDebug) { @@ -146,7 +150,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * * @return The DXFeed instance */ - static std::shared_ptr getInstance() noexcept; + static std::shared_ptr getInstance(); /** * Attaches the given subscription to this feed. This method does nothing if the @@ -164,7 +168,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * @param subscription The subscription. * @see DXFeedSubscription */ - void attachSubscription(std::shared_ptr subscription) noexcept; + void attachSubscription(std::shared_ptr subscription); /** * Detaches the given subscription from this feed. This method does nothing if the @@ -178,7 +182,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * @param subscription The subscription. * @see DXFeedSubscription */ - void detachSubscription(std::shared_ptr subscription) noexcept; + void detachSubscription(std::shared_ptr subscription); /** * Detaches the given subscription from this feed and clears data delivered to this subscription @@ -188,7 +192,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * @param subscription The subscription. * @see DXFeed::detachSubscription() */ - void detachSubscriptionAndClear(std::shared_ptr subscription) noexcept; + void detachSubscriptionAndClear(std::shared_ptr subscription); /** * Creates new subscription for a single event type that is attached to this feed. @@ -202,7 +206,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * @param eventType The type of event * @return The new subscription */ - std::shared_ptr createSubscription(const EventTypeEnum &eventType) noexcept; + std::shared_ptr createSubscription(const EventTypeEnum &eventType); /** * Creates new subscription for multiple event types that is attached to this feed. @@ -235,7 +239,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * @return The new subscription */ template - std::shared_ptr createSubscription(EventTypeIt begin, EventTypeIt end) noexcept { + std::shared_ptr createSubscription(EventTypeIt begin, EventTypeIt end) { if constexpr (Debugger::isDebug) { Debugger::debug("{}::createSubscription(eventTypes = " + namesToString(begin, end) + ")"); } @@ -259,7 +263,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * @param eventTypes The initializer list of event types * @return The new subscription */ - std::shared_ptr createSubscription(std::initializer_list eventTypes) noexcept; + std::shared_ptr createSubscription(std::initializer_list eventTypes); /** * Creates new subscription for multiple event types that is attached to this feed. @@ -281,7 +285,7 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { * @return The new subscription */ template - std::shared_ptr createSubscription(EventTypesCollection &&eventTypes) noexcept { + std::shared_ptr createSubscription(EventTypesCollection &&eventTypes) { if constexpr (Debugger::isDebug) { Debugger::debug(toString() + "::createSubscription(eventTypes = " + namesToString(std::begin(eventTypes), std::end(eventTypes)) + ")"); @@ -294,6 +298,22 @@ struct DXFCPP_EXPORT DXFeed : SharedEntity { return sub; } + /** + * Requests time series of events for the specified event type, symbol, and a range of time. + * @tparam E The type of event. + * @param symbol The symbol. + * @param fromTime The time, inclusive, to request events from (see TimeSeriesEvent::getTime()). + * @param toTime The time, inclusive, to request events to (see TimeSeriesEvent::getTime()). + * Use `std::numeric_limits::max()` or `LLONG_MAX` macro to retrieve events without an + * upper limit on time. + * @return The promise for the result of the request. + */ + template E> + Promise>> getTimeSeriesPromise(const SymbolWrapper &symbol, std::int64_t fromTime, + std::int64_t toTime) const { + return Promise>>(getTimeSeriesPromiseImpl(E::TYPE, symbol, fromTime, toTime)); + } + std::string toString() const noexcept override; }; diff --git a/include/dxfeed_graal_cpp_api/api/DXFeedSubscription.hpp b/include/dxfeed_graal_cpp_api/api/DXFeedSubscription.hpp index 79174fa86..ce23424ad 100644 --- a/include/dxfeed_graal_cpp_api/api/DXFeedSubscription.hpp +++ b/include/dxfeed_graal_cpp_api/api/DXFeedSubscription.hpp @@ -4,6 +4,7 @@ #pragma once #include "../internal/Conf.hpp" +#include "osub/ObservableSubscription.hpp" DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) @@ -34,24 +35,54 @@ struct LastingEvent; /** * Subscription for a set of symbols and event types. */ -class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { +class DXFCPP_EXPORT DXFeedSubscription : public RequireMakeShared, public ObservableSubscription { + public: + static constexpr std::size_t FAKE_CHANGE_LISTENER_ID{static_cast(-1)}; + + /// + using OnEventHandler = SimpleHandler> &)>; + + private: friend struct DXFeed; + inline static std::atomic lastChangeListenerId_{}; + + struct Impl; + + std::unique_ptr impl_; + std::unordered_set eventTypes_; JavaObjectHandle handle_; - std::mutex listenerMutex_{}; + std::mutex eventListenerMutex_{}; JavaObjectHandle eventListenerHandle_; - SimpleHandler> &)> onEvent_{}; - - explicit DXFeedSubscription(const EventTypeEnum &eventType); + OnEventHandler onEvent_{}; + std::unordered_map> changeListeners_; + std::recursive_mutex changeListenersMutex_{}; static JavaObjectHandle createSubscriptionHandleFromEventClassList(const std::unique_ptr &list); void setEventListenerHandle(Id id); - bool tryToSetEventListenerHandle() noexcept; + bool tryToSetEventListenerHandle(); + + void addSymbolsImpl(void *graalSymbolList) const; + + void removeSymbolsImpl(void *graalSymbolList) const; + + void setSymbolsImpl(void *graalSymbolList) const; + + public: + /// The alias to a type of shared pointer to the DXFeedSubscription object + using Ptr = std::shared_ptr; + + /// The alias to a type of unique pointer to the DXFeedSubscription object + using Unique = std::unique_ptr; + + DXFeedSubscription(LockExternalConstructionTag); + + DXFeedSubscription(LockExternalConstructionTag, const EventTypeEnum &eventType); template #if __cpp_concepts @@ -59,72 +90,41 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { { *iter } -> dxfcpp::ConvertibleTo; } #endif - DXFeedSubscription(EventTypeIt begin, EventTypeIt end) - : eventTypes_(begin, end), handle_{}, eventListenerHandle_{}, onEvent_{} { + DXFeedSubscription(LockExternalConstructionTag tag, EventTypeIt begin, EventTypeIt end) : DXFeedSubscription{tag} { if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode Debugger::debug("DXFeedSubscription(eventTypes = " + namesToString(begin, end) + ")"); } + eventTypes_ = std::unordered_set{begin, end}; + auto list = EventClassList::create(eventTypes_.begin(), eventTypes_.end()); handle_ = createSubscriptionHandleFromEventClassList(list); } - DXFeedSubscription(std::initializer_list eventTypes) - : DXFeedSubscription(eventTypes.begin(), eventTypes.end()) { + DXFeedSubscription(LockExternalConstructionTag tag, std::initializer_list eventTypes) + : DXFeedSubscription(tag, eventTypes.begin(), eventTypes.end()) { } template - explicit DXFeedSubscription(EventTypesCollection &&eventTypes) + explicit DXFeedSubscription(LockExternalConstructionTag tag, EventTypesCollection &&eventTypes) #if __cpp_concepts requires requires { { - DXFeedSubscription(std::begin(std::forward(eventTypes)), + DXFeedSubscription(tag, std::begin(std::forward(eventTypes)), std::end(std::forward(eventTypes))) }; } #endif - : DXFeedSubscription(std::begin(std::forward(eventTypes)), + : DXFeedSubscription(tag, std::begin(std::forward(eventTypes)), std::end(std::forward(eventTypes))) { } - void closeImpl() const noexcept; - - void clearImpl() const noexcept; - - bool isClosedImpl() const noexcept; - - void addSymbolImpl(void *graalSymbol) const noexcept; - - void addSymbolsImpl(void *graalSymbolList) const noexcept; - - void removeSymbolImpl(void *graalSymbol) const noexcept; - - void removeSymbolsImpl(void *graalSymbolList) const noexcept; - - void setSymbolsImpl(void *graalSymbolList) const noexcept; - - std::vector getSymbolsImpl() const; - - std::vector getDecoratedSymbolsImpl() const; - - public: - /// The alias to a type of shared pointer to the DXFeedSubscription object - using Ptr = std::shared_ptr; - - /// The alias to a type of unique pointer to the DXFeedSubscription object - using Unique = std::unique_ptr; - /// std::string toString() const noexcept override; - ~DXFeedSubscription() override { - if constexpr (Debugger::isDebug) { - Debugger::debug("DXFeedSubscription{" + handle_.toString() + "}::~DXFeedSubscription()"); - } - - closeImpl(); - } + ~DXFeedSubscription() override; /** * Creates detached subscription for a single event type. @@ -136,18 +136,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param eventType the event type. */ - static std::shared_ptr create(const EventTypeEnum &eventType) { - if constexpr (Debugger::isDebug) { - Debugger::debug("DXFeedSubscription::create(eventType = " + eventType.getName() + ")"); - } - - auto sub = std::shared_ptr(new DXFeedSubscription(eventType)); - auto id = ApiContext::getInstance()->getManager()->registerEntity(sub); - - dxfcpp::ignore_unused(id); - - return sub; - } + static std::shared_ptr create(const EventTypeEnum &eventType); /** * Creates detached subscription for the given collection of event types. @@ -178,10 +167,11 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { #endif static std::shared_ptr create(EventTypeIt begin, EventTypeIt end) { if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode Debugger::debug("DXFeedSubscription::create(eventTypes = " + namesToString(begin, end) + ")"); } - auto sub = std::shared_ptr(new DXFeedSubscription(begin, end)); + auto sub = createShared(begin, end); auto id = ApiContext::getInstance()->getManager()->registerEntity(sub); dxfcpp::ignore_unused(id); @@ -200,14 +190,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * @param eventTypes The event type collection. * @return The new detached subscription for the given collection of event types. */ - static std::shared_ptr create(std::initializer_list eventTypes) { - auto sub = std::shared_ptr(new DXFeedSubscription(eventTypes)); - auto id = ApiContext::getInstance()->getManager()->registerEntity(sub); - - dxfcpp::ignore_unused(id); - - return sub; - } + static std::shared_ptr create(std::initializer_list eventTypes); /** * Creates detached subscription for the given collection of event types. @@ -229,8 +212,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { */ template static std::shared_ptr create(EventTypesCollection &&eventTypes) { - auto sub = - std::shared_ptr(new DXFeedSubscription(std::forward(eventTypes))); + auto sub = createShared(std::forward(eventTypes)); auto id = ApiContext::getInstance()->getManager()->registerEntity(sub); dxfcpp::ignore_unused(id); @@ -243,14 +225,14 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param feed The feed to attach to. */ - void attach(std::shared_ptr feed) noexcept; + void attach(std::shared_ptr feed); /** * Detaches subscription from the specified feed. * * @param feed The feed to detach from. */ - void detach(std::shared_ptr feed) noexcept; + void detach(std::shared_ptr feed); /** * Closes this subscription and makes it permanently detached. @@ -259,13 +241,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * event listeners and subscription change listeners and makes sure that no more listeners * can be added. */ - void close() noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::close()"); - } - - closeImpl(); - } + void close() const; /** * Adds listener for events. @@ -299,7 +275,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * @return The listener id */ template - std::size_t addEventListener(EventListener &&listener) noexcept + std::size_t addEventListener(EventListener &&listener) #if __cpp_concepts requires requires { { listener(std::vector>{}) } -> std::same_as; @@ -307,7 +283,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { #endif { if (!tryToSetEventListenerHandle()) { - return SimpleHandler> &)>::FAKE_ID; + return OnEventHandler::FAKE_ID; } return onEvent_ += listener; @@ -354,7 +330,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * @return The listener id */ template - std::size_t addEventListener(std::function> &)> &&listener) noexcept + std::size_t addEventListener(std::function> &)> &&listener) #if __cpp_concepts requires std::is_base_of_v && (requires { @@ -394,9 +370,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param listenerId The listener id */ - void removeEventListener(std::size_t listenerId) noexcept { - onEvent_ -= listenerId; - } + void removeEventListener(std::size_t listenerId); /** * Returns a reference to an incoming events' handler (delegate), to which listeners can be added and removed. @@ -421,11 +395,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @return The incoming events' handler (delegate) */ - auto &onEvent() noexcept { - tryToSetEventListenerHandle(); - - return onEvent_; - } + OnEventHandler &onEvent(); /** * Adds the specified symbol to the set of subscribed symbols. @@ -443,15 +413,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param symbolWrapper The symbol. */ - void addSymbols(const SymbolWrapper &symbolWrapper) const noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::addSymbols(symbolWrapper = " + toStringAny(symbolWrapper) + ")"); - } - - auto graal = symbolWrapper.toGraalUnique(); - - addSymbolImpl(graal.get()); - } + void addSymbols(const SymbolWrapper &symbolWrapper) const; /** * Removes the specified symbol from the set of subscribed symbols. @@ -467,15 +429,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param symbolWrapper The symbol. */ - void removeSymbols(const SymbolWrapper &symbolWrapper) const noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::removeSymbols(symbolWrapper = " + toStringAny(symbolWrapper) + ")"); - } - - auto graal = symbolWrapper.toGraalUnique(); - - removeSymbolImpl(graal.get()); - } + void removeSymbols(const SymbolWrapper &symbolWrapper) const; /** * Adds the specified collection (using iterators) of symbols to the set of subscribed symbols. @@ -493,6 +447,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { */ template void addSymbols(SymbolIt begin, SymbolIt end) const { if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode Debugger::debug(toString() + "::addSymbols(symbols = " + elementsToString(begin, end) + ")"); } @@ -517,7 +472,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * @param collection The symbols collection */ template - void addSymbols(const SymbolsCollection &collection) const noexcept { + void addSymbols(const SymbolsCollection &collection) const { addSymbols(std::begin(collection), std::end(collection)); } @@ -531,9 +486,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param collection The symbols collection */ - void addSymbols(std::initializer_list collection) const noexcept { - addSymbols(collection.begin(), collection.end()); - } + void addSymbols(std::initializer_list collection) const; /** * Removes the specified collection (using iterators) of symbols from the set of subscribed symbols. @@ -551,6 +504,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { */ template void removeSymbols(SymbolIt begin, SymbolIt end) const { if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode Debugger::debug(toString() + "::removeSymbols(symbols = " + elementsToString(begin, end) + ")"); } @@ -575,7 +529,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * @param collection The symbols collection */ template - void removeSymbols(SymbolsCollection &&collection) const noexcept { + void removeSymbols(SymbolsCollection &&collection) const { removeSymbols(std::begin(collection), std::end(collection)); } @@ -589,9 +543,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param collection The symbols collection */ - void removeSymbols(std::initializer_list collection) const noexcept { - removeSymbols(collection.begin(), collection.end()); - } + void removeSymbols(std::initializer_list collection) const; /** * Changes the set of subscribed symbols so that it contains just the symbols from the specified collection (using @@ -610,6 +562,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { */ template void setSymbols(SymbolIt begin, SymbolIt end) const { if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode Debugger::debug(toString() + "::setSymbols(symbols = " + elementsToString(begin, end) + ")"); } @@ -634,7 +587,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * @param collection The symbols collection */ template - void setSymbols(SymbolsCollection &&collection) const noexcept { + void setSymbols(SymbolsCollection &&collection) const { setSymbols(std::begin(collection), std::end(collection)); } @@ -649,20 +602,12 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @param collection The symbols collection */ - void setSymbols(std::initializer_list collection) const noexcept { - setSymbols(collection.begin(), collection.end()); - } + void setSymbols(std::initializer_list collection) const; /** * Clears the set of subscribed symbols. */ - void clear() const noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::clear()"); - } - - clearImpl(); - } + void clear() const; /** * Returns `true` if this subscription is closed. @@ -671,22 +616,14 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @see DXFeedSubscription::close() */ - bool isClosed() const noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::isClosed()"); - } - - return isClosedImpl(); - } + bool isClosed() override; /** * Returns a set of subscribed event types. * * @return A set of subscribed event types. */ - const std::unordered_set &getEventTypes() const noexcept { - return eventTypes_; - } + std::unordered_set getEventTypes() override; /** * Returns `true` if this subscription contains the corresponding event type. @@ -696,9 +633,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @see DXFeedSubscription::getEventTypes() */ - bool containsEventType(const EventTypeEnum &eventType) const noexcept { - return eventTypes_.contains(eventType); - } + bool containsEventType(const EventTypeEnum &eventType) override; /** * Returns a set of subscribed symbols (depending on the actual implementation of subscription). @@ -708,13 +643,7 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @return A set of subscribed symbols. */ - std::vector getSymbols() const noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::getSymbols()"); - } - - return getSymbolsImpl(); - } + std::vector getSymbols() const; /** * Returns a set of decorated symbols (depending on the actual implementation of subscription). @@ -724,27 +653,11 @@ class DXFCPP_EXPORT DXFeedSubscription : public SharedEntity { * * @return A set of decorated subscribed symbols. */ - std::vector getDecoratedSymbols() noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::getDecoratedSymbols()"); - } - - return getDecoratedSymbolsImpl(); - } - - auto getExecutor() noexcept; - - template void setExecutor(Executor &&executor) noexcept; - - template std::size_t addChangeListener(ChangeListener &&changeListener) noexcept; - - void removeChangeListener(std::size_t changeListenerId) noexcept; - - auto onSymbolsAdded() noexcept; + std::vector getDecoratedSymbols() const; - auto onSymbolsRemoved() noexcept; + std::size_t addChangeListener(std::shared_ptr listener) override; - auto onSubscriptionClosed() noexcept; + void removeChangeListener(std::size_t changeListenerId) override; }; DXFCPP_END_NAMESPACE diff --git a/include/dxfeed_graal_cpp_api/api/DXPublisherObservableSubscription.hpp b/include/dxfeed_graal_cpp_api/api/DXPublisherObservableSubscription.hpp index 01f5b5d36..756d941f7 100644 --- a/include/dxfeed_graal_cpp_api/api/DXPublisherObservableSubscription.hpp +++ b/include/dxfeed_graal_cpp_api/api/DXPublisherObservableSubscription.hpp @@ -40,7 +40,7 @@ struct DXFCPP_EXPORT DXPublisherObservableSubscription : RequireMakeShared getEventTypes() override; bool containsEventType(const EventTypeEnum &eventType) override; std::size_t addChangeListener(std::shared_ptr listener) override; - void removeChangeListener(std::size_t id) override; + void removeChangeListener(std::size_t changeListenerId) override; }; DXFCPP_END_NAMESPACE diff --git a/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscription.hpp b/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscription.hpp index 39e973473..b3cb47758 100644 --- a/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscription.hpp +++ b/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscription.hpp @@ -9,6 +9,7 @@ DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) #include "../../event/IndexedEventSource.hpp" #include "../../symbols/SymbolWrapper.hpp" +#include "../../event/EventTypeEnum.hpp" #include "ObservableSubscriptionChangeListener.hpp" #include @@ -61,7 +62,7 @@ struct DXFCPP_EXPORT ObservableSubscription { /** * Removes subscription change listener by id. This method does nothing if the listener with the given id was not - * installed or was already removed as subscription change listener for this subscription. Otherwise it removes the + * installed or was already removed as subscription change listener for this subscription. Otherwise, it removes the * corresponding listener and immediately invokes ObservableSubscriptionChangeListener::subscriptionClosed() on the * given listener while holding the lock for this subscription. * diff --git a/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscriptionChangeListener.hpp b/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscriptionChangeListener.hpp index d28974ebd..5599f4d1c 100644 --- a/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscriptionChangeListener.hpp +++ b/include/dxfeed_graal_cpp_api/api/osub/ObservableSubscriptionChangeListener.hpp @@ -8,6 +8,7 @@ DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) #include "../../symbols/SymbolWrapper.hpp" +#include "../../entity/SharedEntity.hpp" #include #include diff --git a/include/dxfeed_graal_cpp_api/event/EventMapper.hpp b/include/dxfeed_graal_cpp_api/event/EventMapper.hpp index 9ad6531ef..3879ca98a 100644 --- a/include/dxfeed_graal_cpp_api/event/EventMapper.hpp +++ b/include/dxfeed_graal_cpp_api/event/EventMapper.hpp @@ -15,8 +15,12 @@ DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) DXFCPP_BEGIN_NAMESPACE struct DXFCPP_EXPORT EventMapper { + static std::shared_ptr fromGraal(void* graalNativeEvent); + static std::vector> fromGraalList(void *graalNativeList); + static void freeGraal(void *graalNativeEvent); + template static void *toGraalList(EventIt begin, EventIt end) { if constexpr (Debugger::isDebug) { Debugger::debug("EventMapper::toGraalList(symbols = " + elementsToString(begin, end) + ")"); diff --git a/include/dxfeed_graal_cpp_api/exceptions/JavaException.hpp b/include/dxfeed_graal_cpp_api/exceptions/JavaException.hpp index 7679731ba..0b46f2e77 100644 --- a/include/dxfeed_graal_cpp_api/exceptions/JavaException.hpp +++ b/include/dxfeed_graal_cpp_api/exceptions/JavaException.hpp @@ -27,6 +27,14 @@ struct DXFCPP_EXPORT JavaException : public std::runtime_error { */ JavaException(const std::string &message, const std::string &className, std::string stackTrace); + /** + * Creates an exception using native (GraalVM) Java exception handle + * + * @param exceptionHandle The native Java exception handle. + * @return An exception. + */ + static JavaException create(void* exceptionHandle); + /// Throws a JavaException if it exists (i.e. intercepted by Graal SDK) static void throwIfJavaThreadExceptionExists(); diff --git a/include/dxfeed_graal_cpp_api/internal/JavaObjectHandle.hpp b/include/dxfeed_graal_cpp_api/internal/JavaObjectHandle.hpp index 7474193c6..7dd5b613f 100644 --- a/include/dxfeed_graal_cpp_api/internal/JavaObjectHandle.hpp +++ b/include/dxfeed_graal_cpp_api/internal/JavaObjectHandle.hpp @@ -55,6 +55,47 @@ template struct JavaObjectHandle { std::unique_ptr impl_; }; +template struct JavaObjectHandleList { +#if DXFCPP_DEBUG == 1 + static auto getDebugName() { + return std::string("JavaObjectHandleList<") + typeid(T).name() + ">"; + } +#endif + + using Type = T; + + static DXFCPP_EXPORT void deleter(void *handle) noexcept; + explicit JavaObjectHandleList(void *handle = nullptr) noexcept : impl_{handle, &deleter} { + if constexpr (Debugger::isDebug) { + Debugger::debug(getDebugName() + "(handle = " + dxfcpp::toString(handle) + ")"); + } + } + + JavaObjectHandleList(const JavaObjectHandleList &) = delete; + JavaObjectHandleList(JavaObjectHandleList &&) noexcept = default; + JavaObjectHandleList &operator=(const JavaObjectHandleList &) = delete; + JavaObjectHandleList &operator=(JavaObjectHandleList &&) noexcept = default; + virtual ~JavaObjectHandleList() noexcept = default; + + [[nodiscard]] std::string toString() const noexcept { + if (impl_) + return dxfcpp::toString(impl_.get()); + else + return "nullptr"; + } + + [[nodiscard]] void *get() const noexcept { + return impl_.get(); + } + + explicit operator bool() const noexcept { + return static_cast(impl_); + } + + private: + std::unique_ptr impl_; +}; + DXFCPP_END_NAMESPACE DXFCXX_DISABLE_MSC_WARNINGS_POP() \ No newline at end of file diff --git a/include/dxfeed_graal_cpp_api/isolated/IsolatedCommon.hpp b/include/dxfeed_graal_cpp_api/isolated/IsolatedCommon.hpp index 7e6aaeb5a..e5c8a501b 100644 --- a/include/dxfeed_graal_cpp_api/isolated/IsolatedCommon.hpp +++ b/include/dxfeed_graal_cpp_api/isolated/IsolatedCommon.hpp @@ -46,6 +46,14 @@ constexpr auto throwIfMinusOne = [](auto v) { return JavaException::throwIfMinusOne(v); }; +constexpr auto runGraalFunction(auto graalFunction, auto &&...params) { + return runIsolatedThrow( + [](auto threadHandle, auto &&graalFunction, auto &&...params) { + return graalFunction(static_cast(threadHandle), params...); + }, + graalFunction, params...); +} + constexpr auto runGraalFunctionAndThrow(auto resultCheckerConverter, auto graalFunction, auto &&...params) { return runIsolatedThrow( [](auto threadHandle, auto &&resultCheckerConverter, auto &&graalFunction, auto &&...params) { diff --git a/include/dxfeed_graal_cpp_api/isolated/api/IsolatedDXFeed.hpp b/include/dxfeed_graal_cpp_api/isolated/api/IsolatedDXFeed.hpp new file mode 100644 index 000000000..8fe95894e --- /dev/null +++ b/include/dxfeed_graal_cpp_api/isolated/api/IsolatedDXFeed.hpp @@ -0,0 +1,48 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include "../../internal/Conf.hpp" + +DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) + +#include "../../api/DXFeed.hpp" + +DXFCPP_BEGIN_NAMESPACE + +namespace isolated::api::IsolatedDXFeed { + +/* + +dxfg_feed_t* dxfg_DXFeed_getInstance(graal_isolatethread_t *thread); +dxfg_subscription_t* dxfg_DXFeed_createSubscription(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz); +dxfg_subscription_t* dxfg_DXFeed_createSubscription2(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_list_t *eventClazzes); +dxfg_time_series_subscription_t* dxfg_DXFeed_createTimeSeriesSubscription(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz); +dxfg_time_series_subscription_t* dxfg_DXFeed_createTimeSeriesSubscription2(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_list_t *eventClazzes); +int32_t dxfg_DXFeed_attachSubscription(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_subscription_t *sub); +int32_t dxfg_DXFeed_detachSubscription(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_subscription_t *sub); +int32_t dxfg_DXFeed_detachSubscriptionAndClear(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_subscription_t *sub); +dxfg_event_type_t* dxfg_DXFeed_getLastEventIfSubscribed(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz, dxfg_symbol_t *symbol); +dxfg_event_type_list* dxfg_DXFeed_getIndexedEventsIfSubscribed(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz, dxfg_symbol_t *symbol, const char *source); +dxfg_event_type_list* dxfg_DXFeed_getTimeSeriesIfSubscribed(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz, dxfg_symbol_t *symbol, int64_t from_time, int64_t to_time); +// use dxfg_EventType_new to create an empty structure so that java tries to free up memory when replacing subjects +int32_t dxfg_DXFeed_getLastEvent(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_type_t *event); +int32_t dxfg_DXFeed_getLastEvents(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_type_list *events); +dxfg_promise_event_t* dxfg_DXFeed_getLastEventPromise(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz, dxfg_symbol_t *symbol); +dxfg_promise_list* dxfg_DXFeed_getLastEventsPromises(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz, dxfg_symbol_list *symbols); +dxfg_promise_events_t* dxfg_DXFeed_getIndexedEventsPromise(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t eventClazz, dxfg_symbol_t *symbol, dxfg_indexed_event_source_t* source); +dxfg_promise_events_t* dxfg_DXFeed_getTimeSeriesPromise(graal_isolatethread_t *thread, dxfg_feed_t *feed, dxfg_event_clazz_t clazz, dxfg_symbol_t *symbol, int64_t fromTime, int64_t toTime); + +*/ + + +/* dxfg_promise_events_t* */ void* getTimeSeriesPromise(/* dxfg_feed_t * */ const JavaObjectHandle& feed, /* dxfg_event_clazz_t */ const EventTypeEnum &eventType, /* dxfg_symbol_t * */ const SymbolWrapper &symbol, std::int64_t fromTime, + std::int64_t toTime); + + +} + +DXFCPP_END_NAMESPACE + +DXFCXX_DISABLE_MSC_WARNINGS_POP() \ No newline at end of file diff --git a/include/dxfeed_graal_cpp_api/isolated/api/IsolatedDXFeedSubscription.hpp b/include/dxfeed_graal_cpp_api/isolated/api/IsolatedDXFeedSubscription.hpp new file mode 100644 index 000000000..1bd18a5e0 --- /dev/null +++ b/include/dxfeed_graal_cpp_api/isolated/api/IsolatedDXFeedSubscription.hpp @@ -0,0 +1,235 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include "../../internal/Conf.hpp" + +DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) + +#include + +#include "../../api/DXFeedSubscription.hpp" + +DXFCPP_BEGIN_NAMESPACE + +namespace isolated::api::IsolatedDXFeedSubscription { + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_new` in isolation. + * + * @param eventType The subscription's event type. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +JavaObjectHandle /* dxfg_subscription_t* */ +create(/* dxfg_event_clazz_t */ const EventTypeEnum &eventType); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_new2` in isolation. + * + * @param eventClassList The subscription's event types. + * + * @throws std::invalid_argument if eventClassList is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +JavaObjectHandle /* dxfg_subscription_t* */ +create(/* dxfg_event_clazz_list_t * */ const std::unique_ptr &eventClassList); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_close` in isolation. + * + * @param sub The subscription's handle. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ close(/* dxfg_subscription_t * */ const JavaObjectHandle &sub); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_addEventListener` in isolation. + * + * @param sub The subscription's handle. + * @param listener The listener's handle. + * @throws std::invalid_argument if DXFeedSubscription's or DXFeedEventListener's handle is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ +addEventListener(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_feed_event_listener_t * */ const JavaObjectHandle &listener); + +// int32_t dxfg_DXFeedSubscription_removeEventListener(graal_isolatethread_t *thread, dxfg_subscription_t *sub, +// dxfg_feed_event_listener_t *listener); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_addSymbol` in isolation. + * + * @param sub The subscription's handle. + * @param symbol The subscription's symbol. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid or the symbol is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ addSymbol(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_t * */ void *symbol); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_addSymbols` in isolation. + * + * @param sub The subscription's handle. + * @param symbols The subscription's symbols. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid or the symbols is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ addSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_list * */ void *symbols); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_removeSymbol` in isolation. + * + * @param sub The subscription's handle. + * @param symbol The subscription's symbol. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid or the symbol is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ removeSymbol(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_t * */ void *symbol); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_removeSymbols` in isolation. + * + * @param sub The subscription's handle. + * @param symbols The subscription's symbols. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid or the symbols is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ removeSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_list * */ void *symbols); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_clear` in isolation. + * + * @param sub The subscription's handle. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ clear(/* dxfg_subscription_t * */ const JavaObjectHandle &sub); + +// int32_t dxfg_DXFeedSubscription_attach(graal_isolatethread_t *thread, dxfg_subscription_t *sub, dxfg_feed_t *feed); + +// int32_t dxfg_DXFeedSubscription_detach(graal_isolatethread_t *thread, dxfg_subscription_t *sub, dxfg_feed_t *feed); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_isClosed` in isolation. + * + * @param sub The subscription's handle. + * @return `true` if subscription is closed. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +bool /* int32_t */ isClosed(/* dxfg_subscription_t * */ const JavaObjectHandle &sub); + +// dxfg_event_clazz_list_t* dxfg_DXFeedSubscription_getEventTypes(graal_isolatethread_t *thread, dxfg_subscription_t +// *sub); + +// int32_t dxfg_DXFeedSubscription_containsEventType(graal_isolatethread_t *thread, dxfg_subscription_t *sub, +// dxfg_event_clazz_t eventClazz); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_getSymbols` in isolation. + * + * @param sub The subscription's handle. + * @return The subscription's symbols. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +std::vector /* dxfg_symbol_list* */ getSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub); + +// int32_t dxfg_DXFeedSubscription_setSymbol(graal_isolatethread_t *thread, dxfg_subscription_t *sub, dxfg_symbol_t *symbol); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_setSymbols` in isolation. + * + * @param sub The subscription's handle. + * @param symbols The subscription's symbols. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid or the symbols is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ setSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, /* dxfg_symbol_list * */ void* symbols); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_getDecoratedSymbols` in isolation. + * + * @param sub The subscription's handle. + * @return The subscription's decorated symbols. + * @throws std::invalid_argument if DXFeedSubscription's handle is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +std::vector /* dxfg_symbol_list* */ getDecoratedSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub); + +// dxfg_executor_t* dxfg_DXFeedSubscription_getExecutor(graal_isolatethread_t *thread, dxfg_subscription_t *sub); + +// int32_t dxfg_DXFeedSubscription_setExecutor(graal_isolatethread_t *thread, dxfg_executor_t *executor); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_addChangeListener` in isolation. + * + * @param sub The subscription's handle. + * @param listener The listener's handle. + * @throws std::invalid_argument if DXFeedSubscription's or ObservableSubscriptionChangeListener's handle + * is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ addChangeListener( + /* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_observable_subscription_change_listener_t * */ const JavaObjectHandle + &listener); + +/** + * Calls the Graal SDK function `dxfg_DXFeedSubscription_removeChangeListener` in isolation. + * + * @param sub The subscription's handle. + * @param listener The listener's handle. + * @throws std::invalid_argument if DXFeedSubscription's or ObservableSubscriptionChangeListener's handle + * is invalid. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ removeChangeListener( + /* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_observable_subscription_change_listener_t * */ const JavaObjectHandle + &listener); + +namespace DXFeedEventListener { + +/** + * Calls the Graal SDK function `dxfg_DXFeedEventListener_new` in isolation. + * @param userFunc A user function that is used as a callback for the listener. + * @param userData User data, which is placed each time as a callback parameter when called from listener. + * @return The DXFeedEventListener's handle. + * + * @throws std::invalid_argument if userFunc is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +JavaObjectHandle /* dxfg_feed_event_listener_t* */ +create(/* dxfg_feed_event_listener_function */ void *userFunc, void *userData); + +} // namespace DXFeedEventListener + +} // namespace isolated::api::IsolatedDXFeedSubscription + +DXFCPP_END_NAMESPACE + +DXFCXX_DISABLE_MSC_WARNINGS_POP() \ No newline at end of file diff --git a/include/dxfeed_graal_cpp_api/isolated/promise/IsolatedPromise.hpp b/include/dxfeed_graal_cpp_api/isolated/promise/IsolatedPromise.hpp new file mode 100644 index 000000000..6ad680278 --- /dev/null +++ b/include/dxfeed_graal_cpp_api/isolated/promise/IsolatedPromise.hpp @@ -0,0 +1,159 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include "../../internal/Conf.hpp" + +DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) + +#include "../../event/EventType.hpp" +#include "../../exceptions/JavaException.hpp" + +#include +#include + +DXFCPP_BEGIN_NAMESPACE + +namespace isolated::promise::IsolatedPromise { + +/** + * Calls the Graal SDK function `dxfg_Promise_isDone` in isolation. + * + * @param promise The promise's handle. + * @return `true` when computation has completed normally or exceptionally or was cancelled. + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +bool /* int32_t */ isDone(/* dxfg_promise_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_hasResult` in isolation. + * + * @param promise The promise's handle. + * @return `true` when computation has completed normally + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +bool /* int32_t */ hasResult(/* dxfg_promise_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_hasException` in isolation. + * + * @param promise The promise's handle. + * @return `true` when computation has completed exceptionally or was cancelled. + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +bool /* int32_t */ hasException(/* dxfg_promise_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_isCancelled` in isolation. + * + * @param promise The promise's handle. + * @return `true` when computation was cancelled. + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +bool /* int32_t */ isCancelled(/* dxfg_promise_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_EventType_getResult` in isolation. + * + * @param promise The promise's handle. + * @return event by promise + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +std::shared_ptr /* dxfg_event_type_t* */ getResult(/* dxfg_promise_event_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_List_EventType_getResult` in isolation. + * + * @param promise The promise's handle. + * @return events by promise + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +std::vector> /* dxfg_event_type_list* */ getResults(/* dxfg_promise_events_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_getException` in isolation. + * + * @param promise The promise's handle. + * @return exception by promise + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +JavaException /* dxfg_exception_t* */ getException(/* dxfg_promise_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_await` in isolation. + * + * @param promise The promise's handle. + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ await(/* dxfg_promise_t * */ void* promise); + +/** + * Calls the Graal SDK function `dxfg_Promise_await2` in isolation. + * + * @param promise The promise's handle. + * @param timeoutInMilliseconds The promise's timeout. + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ await(/* dxfg_promise_t * */ void* promise, std::int32_t timeoutInMilliseconds); + +/** + * Calls the Graal SDK function `dxfg_Promise_awaitWithoutException` in isolation. + * + * @param promise The promise's handle. + * @param timeoutInMilliseconds The promise's timeout. + * @return `true` if the computation has completed normally; `false` when wait timed out. + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +bool /* int32_t */ awaitWithoutException(/* dxfg_promise_t * */ void* promise, std::int32_t timeoutInMilliseconds); + +/** + * Calls the Graal SDK function `dxfg_Promise_cancel` in isolation. + * + * @param promise The promise's handle. + * @throws std::invalid_argument if promise handle is nullptr. + * @throws JavaException if something happened with the dxFeed API backend. + * @throws GraalException if something happened with the GraalVM. + */ +void /* int32_t */ cancel(/* dxfg_promise_t * */ void* promise); + +/* + +int32_t dxfg_Promise_List_EventType_complete(graal_isolatethread_t *thread, dxfg_promise_t *promise, dxfg_event_type_list* events); +int32_t dxfg_Promise_EventType_complete(graal_isolatethread_t *thread, dxfg_promise_t *promise, dxfg_event_type_t* event); +int32_t dxfg_Promise_completeExceptionally(graal_isolatethread_t *thread, dxfg_promise_t *promise, dxfg_exception_t* exception); +int32_t dxfg_Promise_whenDone(graal_isolatethread_t *thread, dxfg_promise_t *promise, dxfg_promise_handler_function promise_handler_function, void *user_data); +int32_t dxfg_Promise_whenDoneAsync(graal_isolatethread_t *thread, dxfg_promise_t *promise, dxfg_promise_handler_function promise_handler_function, void *user_data, dxfg_executor_t* executor); +dxfg_promise_t* dxfg_Promise_completed(graal_isolatethread_t *thread, dxfg_promise_t *promise, dxfg_java_object_handler *handler); +dxfg_promise_t* dxfg_Promise_failed(graal_isolatethread_t *thread, dxfg_promise_t *promise, dxfg_exception_t* exception); + +dxfg_promise_t* dxfg_Promises_allOf(graal_isolatethread_t *thread, dxfg_promise_list *promises); + +*/ + + +} + +DXFCPP_END_NAMESPACE + +DXFCXX_DISABLE_MSC_WARNINGS_POP() \ No newline at end of file diff --git a/include/dxfeed_graal_cpp_api/promise/Promise.hpp b/include/dxfeed_graal_cpp_api/promise/Promise.hpp new file mode 100644 index 000000000..5bfc5c809 --- /dev/null +++ b/include/dxfeed_graal_cpp_api/promise/Promise.hpp @@ -0,0 +1,352 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include "../exceptions/JavaException.hpp" +#include "../internal/Conf.hpp" + +DXFCXX_DISABLE_MSC_WARNINGS_PUSH(4251) + +#include +#include +#include + +DXFCPP_BEGIN_NAMESPACE + +struct EventType; +struct JavaException; + +template +concept Derived = std::is_base_of_v; + +template EDerived> +std::shared_ptr convertEvent(const std::shared_ptr &source) { + return source->template sharedAs(); +} + +template EDerived> +std::vector> convertEvents(const std::vector> &source) { + std::vector> result{}; + + result.reserve(source.size()); + + for (const auto &e : source) { + result.emplace_back(e->template sharedAs()); + } + + return result; +} + +struct PromiseImpl { + protected: + void *handle = nullptr; + + public: + explicit PromiseImpl(void *handle); + + bool isDone() const; + bool hasResult() const; + bool hasException() const; + bool isCancelled() const; + JavaException getException() const; + void await() const; + void await(std::int32_t timeoutInMilliseconds) const; + bool awaitWithoutException(std::int32_t timeoutInMilliseconds) const; + void cancel() const; +}; + +struct EventPromiseImpl : PromiseImpl { + void *handle = nullptr; + + explicit EventPromiseImpl(void *handle); + ~EventPromiseImpl(); + std::shared_ptr getResult() const; +}; + +struct EventsPromiseImpl : PromiseImpl { + void *handle = nullptr; + + explicit EventsPromiseImpl(void *handle); + ~EventsPromiseImpl(); + std::vector> getResult() const; +}; + +/** + * Mixin for wrapping calls to common promise methods. + * + * @tparam P The promise type + */ +template struct CommonPromiseMixin { + /** + * Returns `true` when computation has completed normally, or exceptionally, or was cancelled. + * + * @return `true` when computation has completed. + */ + bool isDone() const { + return static_cast(this)->impl.isDone(); + } + + /** + * Returns `true` when computation has completed normally. + * Use ::getResult() method to get the result of the computation. + * @return `true` when computation has completed normally. + * @see ::getResult() + */ + bool hasResult() const { + return static_cast(this)->impl.hasResult(); + } + + /** + * Returns `true` when computation has completed exceptionally or was cancelled. + * Use ::getException() method to get the exceptional outcome of the computation. + * @return `true` when computation has completed exceptionally or was cancelled. + */ + bool hasException() const { + return static_cast(this)->impl.hasException(); + } + + /** + * Returns `true` when computation was cancelled. + * Use ::getException() method to get the corresponding CancellationException. + * @return `true` when computation was cancelled. + * @see ::getException() + */ + bool isCancelled() const { + return static_cast(this)->impl.isCancelled(); + } + + /** + * Returns exceptional outcome of computation. If computation has no ::hasException() exception, + * then this method returns an exception with a message "null". If computation has completed exceptionally or was + * cancelled, then the result of this method is not an exception with a message "null". If computation was @ref + * ::isCancelled() "cancelled", then this method returns "an instance of CancellationException". + * + * @return exceptional outcome of computation. + * @see ::hasException() + */ + JavaException getException() const { + return static_cast(this)->impl.getException(); + } + + /** + * Wait for computation to complete or timeout or throw an exception in case of exceptional completion. + * If the wait is interrupted, then the computation is @ref ::cancel() "cancelled", + * the interruption flag on the current thread is set, and "CancellationException" is thrown. + * + *

If the wait times out, then the computation is @ref ::cancel() "cancelled" and this method returns `false`. + * Use this method in the code that shall continue normal execution in case of timeout. + * + * @param timeoutInMilliseconds The timeout. + * @return `true` if the computation has completed normally; `false` when wait timed out. + * @throws CancellationException if computation was cancelled. + * @throws PromiseException if computation has completed exceptionally. + */ + bool awaitWithoutException(std::int32_t timeoutInMilliseconds) const { + return static_cast(this)->impl.awaitWithoutException(timeoutInMilliseconds); + } + + /** + * Wait for computation to complete or timeout or throw an exception in case of exceptional completion. + * If the wait is interrupted, then the computation is @ref ::cancel() "cancelled", + * the interruption flag on the current thread is set, and "CancellationException" is thrown. + * + *

If the wait times out, then the computation is @ref ::cancel() "cancelled" and this method returns `false`. + * Use this method in the code that shall continue normal execution in case of timeout. + * + * @param timeoutInMilliseconds The timeout. + * @return `true` if the computation has completed normally; `false` when wait timed out. + * @throws CancellationException if computation was cancelled. + * @throws PromiseException if computation has completed exceptionally. + */ + bool awaitWithoutException(const std::chrono::milliseconds &timeoutInMilliseconds) const { + auto timeout = timeoutInMilliseconds.count(); + + if (timeout > std::numeric_limits::max()) { + timeout = std::numeric_limits::max(); + } + + return static_cast(this)->impl.awaitWithoutException(timeout); + } + + /** + * Cancels computation. This method does nothing if computation has already @ref ::isDone() "completed". + * + *

If cancelled, then ::getException() will return "CancellationException", + * @ref ::isDone() "isDone", @ref ::isCancelled() "isCancelled", and @ref ::hasException() "hasException" will + * return `true`, all handlers that were installed with `whenDone` method are notified by invoking their + * `promiseDone` method, and all waiters on @ref ::await() "join" method throw "CancellationException". + */ + void cancel() const { + static_cast(this)->impl.cancel(); + } +}; + +/** + * Mixin for wrapping Promise method calls for a single event. + * @tparam E The event type. + * @tparam P The promise type. + */ +template struct EventPromiseMixin { + /** + * Returns result of computation. If computation has no @ref CommonPromiseMixin::hasResult() "result", then + * this method returns `std::shared_ptr(nullptr)`. + * + * @return The result of computation. + * @see CommonPromiseMixin::hasResult() + */ + std::shared_ptr getResult() const { + return convertEvent(static_cast(this)->impl.getResult()); + } + + /** + * Wait for computation to complete and return its result or throw an exception in case of exceptional completion. + * @return result of computation. + * @throws CancellationException if computation was cancelled. + * @throws PromiseException if computation has completed exceptionally. + */ + std::shared_ptr await() const { + static_cast(this)->impl.await(); + + return getResult(); + } + + /** + * Wait for computation to complete or timeout and return its result or throw an exception in case of exceptional + * completion or timeout. + * + * @param timeoutInMilliseconds The timeout. + * @return The result of computation. + * @throws CancellationException if computation was cancelled or timed out. + * @throws PromiseException if computation has completed exceptionally. + */ + std::shared_ptr await(std::int32_t timeoutInMilliseconds) const & { + static_cast(this)->impl.await(timeoutInMilliseconds); + + return getResult(); + } + + /** + * Wait for computation to complete or timeout and return its result or throw an exception in case of exceptional + * completion or timeout. + * + * @param timeoutInMilliseconds The timeout. + * @return The result of computation. + * @throws CancellationException if computation was cancelled or timed out. + * @throws PromiseException if computation has completed exceptionally. + */ + std::shared_ptr await(const std::chrono::milliseconds &timeoutInMilliseconds) const & { + auto timeout = timeoutInMilliseconds.count(); + + if (timeout > std::numeric_limits::max()) { + timeout = std::numeric_limits::max(); + } + + static_cast(this)->impl.await(timeout); + + return getResult(); + } +}; + +template struct EventsPromiseMixin { + /** + * Returns result of computation. If computation has no @ref CommonPromiseMixin::hasResult() "result", then + * this method returns an empty ollection. + * + * @return The result of computation. + * @see CommonPromiseMixin::hasResult() + */ + std::vector> getResult() const { + return convertEvents(static_cast(this)->impl.getResult()); + } + + /** + * Wait for computation to complete and return its result or throw an exception in case of exceptional completion. + * @return result of computation. + * @throws CancellationException if computation was cancelled. + * @throws PromiseException if computation has completed exceptionally. + */ + std::vector> await() const { + static_cast(this)->impl.await(); + + return getResult(); + } + + /** + * Wait for computation to complete or timeout and return its result or throw an exception in case of exceptional + * completion or timeout. + * + * @param timeoutInMilliseconds The timeout. + * @return The result of computation. + * @throws CancellationException if computation was cancelled or timed out. + * @throws PromiseException if computation has completed exceptionally. + */ + std::vector> await(std::int32_t timeoutInMilliseconds) const & { + static_cast(this)->impl.await(timeoutInMilliseconds); + + return getResult(); + } + + /** + * Wait for computation to complete or timeout and return its result or throw an exception in case of exceptional + * completion or timeout. + * + * @param timeoutInMilliseconds The timeout. + * @return The result of computation. + * @throws CancellationException if computation was cancelled or timed out. + * @throws PromiseException if computation has completed exceptionally. + */ + std::vector> await(const std::chrono::milliseconds &timeoutInMilliseconds) const & { + auto timeout = timeoutInMilliseconds.count(); + + if (timeout > std::numeric_limits::max()) { + timeout = std::numeric_limits::max(); + } + + static_cast(this)->impl.await(timeout); + + return getResult(); + } +}; + +/** + * Result of a computation that will be completed normally or exceptionally in the future. + * @tparam T The result type. + */ +template struct Promise {}; + +/** + * Result of an event receiving that will be completed normally or exceptionally in the future. + * @tparam E The event type. + */ +template +struct Promise> : CommonPromiseMixin>>, + EventPromiseMixin>> { + friend struct CommonPromiseMixin; + friend struct EventPromiseMixin; + + EventsPromiseImpl impl; + + explicit Promise(void *handle) : impl(handle) { + } +}; + +/** + * Result of an collection of events receiving that will be completed normally or exceptionally in the future. + * @tparam E The event type. + */ +template +struct Promise>> : CommonPromiseMixin>>>, + EventsPromiseMixin>>> { + friend struct CommonPromiseMixin; + friend struct EventsPromiseMixin; + + EventsPromiseImpl impl; + + explicit Promise(void *handle) : impl(handle) { + } +}; + +DXFCPP_END_NAMESPACE + +DXFCXX_DISABLE_MSC_WARNINGS_POP() \ No newline at end of file diff --git a/samples/cpp/FetchDailyCandles/CMakeLists.txt b/samples/cpp/FetchDailyCandles/CMakeLists.txt new file mode 100644 index 000000000..e934ceab0 --- /dev/null +++ b/samples/cpp/FetchDailyCandles/CMakeLists.txt @@ -0,0 +1,56 @@ +# Copyright (c) 2024 Devexperts LLC. +# SPDX-License-Identifier: MPL-2.0 + +cmake_minimum_required(VERSION 3.21) + +if (POLICY CMP0092) + cmake_policy(SET CMP0092 NEW) +endif () + +if (POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif () + +project(FetchDailyCandles LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_C_STANDARD 11) +set(CXX_EXTENSIONS OFF) +set(C_EXTENSIONS OFF) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(CMAKE_MACOSX_RPATH ON) + set(CMAKE_SKIP_BUILD_RPATH ON) + set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF) + set(CMAKE_BUILD_RPATH_USE_ORIGIN ON) + set(CMAKE_INSTALL_RPATH "@loader_path/../${CMAKE_INSTALL_LIBDIR};@loader_path;@executable_path;@executable_path/../Frameworks") +elseif (UNIX) + set(CMAKE_SKIP_BUILD_RPATH ON) + set(CMAKE_BUILD_WITH_INSTALL_RPATH ON) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH OFF) + set(CMAKE_BUILD_RPATH_USE_ORIGIN ON) + set(CMAKE_INSTALL_RPATH "$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:$ORIGIN/../lib64:$ORIGIN/../lib:$ORIGIN") +endif () + +add_executable(${PROJECT_NAME} src/main.cpp) + +target_link_libraries(${PROJECT_NAME} PRIVATE dxfcxx::static) + +if (DXFCXX_FEATURE_STACKTRACE) + LinkStacktrace(${PROJECT_NAME}) +endif () + +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different + $ + ${CMAKE_CURRENT_SOURCE_DIR}/dxfeed.properties + $) + +if (DXFCXX_INSTALL AND DXFCXX_INSTALL_SAMPLES) + install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}) + install(FILES "dxfeed.properties" DESTINATION ${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}) + + if (WIN32) + install(FILES $ DESTINATION ${CMAKE_INSTALL_BINDIR}/${PROJECT_NAME}) + endif () +endif () \ No newline at end of file diff --git a/samples/cpp/FetchDailyCandles/dxfeed.properties b/samples/cpp/FetchDailyCandles/dxfeed.properties new file mode 100644 index 000000000..6d1f9e30b --- /dev/null +++ b/samples/cpp/FetchDailyCandles/dxfeed.properties @@ -0,0 +1,5 @@ +# Copyright (c) 2024 Devexperts LLC. +# SPDX-License-Identifier: MPL-2.0 + +# Connection address for an endpoint with role Feed and OnDemandFeed. +dxfeed.address=demo.dxfeed.com:7300 diff --git a/samples/cpp/FetchDailyCandles/src/main.cpp b/samples/cpp/FetchDailyCandles/src/main.cpp new file mode 100644 index 000000000..a2d653922 --- /dev/null +++ b/samples/cpp/FetchDailyCandles/src/main.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include +#include + +void fetchAndPrint(const dxfcpp::CandleSymbol &candleSymbol, std::int64_t toTime, std::int64_t fromTime) { + // Use default DXFeed instance for that data feed address is defined by dxfeed.properties file + auto result = dxfcpp::DXFeed::getInstance() + ->getTimeSeriesPromise(candleSymbol, fromTime, toTime) + .await(std::chrono::seconds(5)); + + for (const auto &candle : result) { + std::cout << candle->toString() << "\n"; + } +} + +// Fetches last 20 days of candles for a specified symbol, prints them, and exits. +int main(int argc, char *argv[]) { + static const auto DAYS = 20; + + using namespace dxfcpp; + using namespace std::string_literals; + + try { + if (argc < 2) { + std::cout << R"( +Usage: +FetchDailyCandles + +Where: + baseSymbol - Is security symbol (e.g. IBM, AAPL, SPX etc.) +)"; + return 0; + } + + // Specified instrument name, for example AAPL, IBM, MSFT, etc. + auto baseSymbol = argv[1]; + + auto candleSymbol = CandleSymbol::valueOf(baseSymbol, CandlePeriod::DAY); + auto toTime = dxfcpp::now(); + auto fromTime = toTime - std::chrono::duration_cast(std::chrono::days(DAYS)).count(); + + std::cout << "Fetching last " << DAYS << " days of candles for " << baseSymbol << "\n"; + + fetchAndPrint(candleSymbol, toTime, fromTime); + } catch (const JavaException &e) { + std::cerr << e.what() << '\n'; + std::cerr << e.getStackTrace() << '\n'; + } catch (const GraalException &e) { + std::cerr << e.what() << '\n'; + std::cerr << e.getStackTrace() << '\n'; + } +} diff --git a/src/api/DXEndpoint.cpp b/src/api/DXEndpoint.cpp index 440d78204..b494b7cf3 100644 --- a/src/api/DXEndpoint.cpp +++ b/src/api/DXEndpoint.cpp @@ -140,7 +140,7 @@ std::shared_ptr DXEndpoint::create(void *endpointHandle, DXEndpoint: auto id = ApiContext::getInstance()->getManager()->registerEntity(endpoint); endpoint->stateChangeListenerHandle_ = isolated::api::IsolatedDXEndpoint::StateChangeListener::create( - dxfcpp::bit_cast(&DXEndpoint::Impl::onPropertyChange), dxfcpp::bit_cast(id.getValue())); + dxfcpp::bit_cast(&Impl::onPropertyChange), dxfcpp::bit_cast(id.getValue())); isolated::api::IsolatedDXEndpoint::addStateChangeListener(endpoint->handle_, endpoint->stateChangeListenerHandle_); return endpoint; diff --git a/src/api/DXFeed.cpp b/src/api/DXFeed.cpp index 087c05fc3..1925bd97e 100644 --- a/src/api/DXFeed.cpp +++ b/src/api/DXFeed.cpp @@ -16,7 +16,7 @@ DXFCPP_BEGIN_NAMESPACE -std::shared_ptr DXFeed::getInstance() noexcept { +std::shared_ptr DXFeed::getInstance() { if constexpr (Debugger::isDebug) { Debugger::debug("DXFeed::getInstance()"); } @@ -24,7 +24,7 @@ std::shared_ptr DXFeed::getInstance() noexcept { return DXEndpoint::getInstance()->getFeed(); } -void DXFeed::attachSubscription(std::shared_ptr subscription) noexcept { +void DXFeed::attachSubscription(std::shared_ptr subscription) { if constexpr (Debugger::isDebug) { Debugger::debug(toString() + "::attachSubscription(" + subscription->toString() + ")"); } @@ -43,7 +43,7 @@ void DXFeed::attachSubscription(std::shared_ptr subscription } } -void DXFeed::detachSubscription(std::shared_ptr subscription) noexcept { +void DXFeed::detachSubscription(std::shared_ptr subscription) { if constexpr (Debugger::isDebug) { Debugger::debug(toString() + "::detachSubscription(" + subscription->toString() + ")"); } @@ -62,7 +62,7 @@ void DXFeed::detachSubscription(std::shared_ptr subscription } } -void DXFeed::detachSubscriptionAndClear(std::shared_ptr subscription) noexcept { +void DXFeed::detachSubscriptionAndClear(std::shared_ptr subscription) { if constexpr (Debugger::isDebug) { Debugger::debug(toString() + "::detachSubscriptionAndClear(" + subscription->toString() + ")"); } @@ -81,7 +81,7 @@ void DXFeed::detachSubscriptionAndClear(std::shared_ptr subs } } -std::shared_ptr DXFeed::createSubscription(const EventTypeEnum &eventType) noexcept { +std::shared_ptr DXFeed::createSubscription(const EventTypeEnum &eventType) { if constexpr (Debugger::isDebug) { Debugger::debug(toString() + "::createSubscription(eventType = " + eventType.getName() + ")"); } @@ -93,8 +93,7 @@ std::shared_ptr DXFeed::createSubscription(const EventTypeEn return sub; } -std::shared_ptr -DXFeed::createSubscription(std::initializer_list eventTypes) noexcept { +std::shared_ptr DXFeed::createSubscription(std::initializer_list eventTypes) { if constexpr (Debugger::isDebug) { Debugger::debug(toString() + "::createSubscription(eventTypes = " + namesToString(eventTypes.begin(), eventTypes.end()) + ")"); @@ -122,6 +121,11 @@ std::shared_ptr DXFeed::create(void *feedHandle) { return feed; } +void *DXFeed::getTimeSeriesPromiseImpl(const EventTypeEnum &eventType, const SymbolWrapper &symbol, + std::int64_t fromTime, std::int64_t toTime) const { + return isolated::api::IsolatedDXFeed::getTimeSeriesPromise(handle_, eventType, symbol, fromTime, toTime); +} + std::string DXFeed::toString() const noexcept { return fmt::format("DXFeed{{{}}}", handle_.toString()); } diff --git a/src/api/DXFeedSubscription.cpp b/src/api/DXFeedSubscription.cpp index 98bda917c..3ce0dc80d 100644 --- a/src/api/DXFeedSubscription.cpp +++ b/src/api/DXFeedSubscription.cpp @@ -15,245 +15,253 @@ DXFCPP_BEGIN_NAMESPACE -void DXFeedSubscription::attach(std::shared_ptr feed) noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::attach(feed = " + feed->toString() + ")"); +struct DXFeedSubscription::Impl { + static void onEvents(graal_isolatethread_t * /*thread*/, dxfg_event_type_list *graalNativeEvents, void *userData) { + auto id = Id::from(dxfcpp::bit_cast::ValueType>(userData)); + auto sub = ApiContext::getInstance()->getManager()->getEntity(id); + + if (sub) { + auto &&events = EventMapper::fromGraalList(static_cast(graalNativeEvents)); + + sub->onEvent_(events); + } } +}; - feed->attachSubscription(sharedAs()); +JavaObjectHandle +DXFeedSubscription::createSubscriptionHandleFromEventClassList(const std::unique_ptr &list) { + return isolated::api::IsolatedDXFeedSubscription::create(list); } -void DXFeedSubscription::detach(std::shared_ptr feed) noexcept { - if constexpr (Debugger::isDebug) { - Debugger::debug(toString() + "::detach(feed = " + feed->toString() + ")"); +void DXFeedSubscription::setEventListenerHandle(Id id) { + eventListenerHandle_ = isolated::api::IsolatedDXFeedSubscription::DXFeedEventListener::create( + dxfcpp::bit_cast(&Impl::onEvents), dxfcpp::bit_cast(id.getValue())); + + isolated::api::IsolatedDXFeedSubscription::addEventListener(handle_, eventListenerHandle_); +} + +bool DXFeedSubscription::tryToSetEventListenerHandle() { + std::lock_guard lock{eventListenerMutex_}; + + if (!eventListenerHandle_) { + auto idOpt = + ApiContext::getInstance()->getManager()->getId(sharedAs()); + + if (!idOpt) { + return false; + } + + setEventListenerHandle(idOpt.value()); } - feed->detachSubscription(sharedAs()); + return true; } -void DXFeedSubscription::addSymbolImpl(void *graalSymbol) const noexcept { - if (!handle_) { - return; +void DXFeedSubscription::addSymbolsImpl(void *graalSymbolList) const { + isolated::api::IsolatedDXFeedSubscription::addSymbols(handle_, graalSymbolList); +} + +void DXFeedSubscription::removeSymbolsImpl(void *graalSymbolList) const { + isolated::api::IsolatedDXFeedSubscription::removeSymbols(handle_, graalSymbolList); +} + +void DXFeedSubscription::setSymbolsImpl(void *graalSymbolList) const { + isolated::api::IsolatedDXFeedSubscription::setSymbols(handle_, graalSymbolList); +} + +DXFeedSubscription::DXFeedSubscription(LockExternalConstructionTag) + : impl_(std::make_unique()) { +} + +DXFeedSubscription::DXFeedSubscription(LockExternalConstructionTag tag, const EventTypeEnum &eventType) + : DXFeedSubscription{tag} { + if constexpr (Debugger::isDebug) { + Debugger::debug("DXFeedSubscription(eventType = " + eventType.getName() + ")"); } - runIsolatedOrElse( - [handle = static_cast(handle_.get()), graalSymbol](auto threadHandle) { - return dxfg_DXFeedSubscription_addSymbol(static_cast(threadHandle), handle, - static_cast(graalSymbol)) == 0; - }, - false); + eventTypes_ = std::unordered_set{eventType}; + handle_ = isolated::api::IsolatedDXFeedSubscription::create(eventType); } -void DXFeedSubscription::addSymbolsImpl(void *graalSymbolList) const noexcept { - if (!handle_) { - return; +std::string DXFeedSubscription::toString() const noexcept { + return fmt::format("DXFeedSubscription{{{}}}", handle_.toString()); +} + +DXFeedSubscription::~DXFeedSubscription() { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug("DXFeedSubscription{" + handle_.toString() + "}::~DXFeedSubscription()"); } - runIsolatedOrElse( - [handle = static_cast(handle_.get()), graalSymbolList](auto threadHandle) { - return dxfg_DXFeedSubscription_addSymbols(static_cast(threadHandle), handle, - static_cast(graalSymbolList)) == 0; - }, - false); + close(); } -void DXFeedSubscription::removeSymbolImpl(void *graalSymbol) const noexcept { - if (!handle_) { - return; +std::shared_ptr DXFeedSubscription::create(const EventTypeEnum &eventType) { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug("DXFeedSubscription::create(eventType = " + eventType.getName() + ")"); } - runIsolatedOrElse( - [handle = static_cast(handle_.get()), graalSymbol](auto threadHandle) { - return dxfg_DXFeedSubscription_removeSymbol(static_cast(threadHandle), handle, - static_cast(graalSymbol)) == 0; - }, - false); + auto sub = createShared(eventType); + auto id = ApiContext::getInstance()->getManager()->registerEntity(sub); + + dxfcpp::ignore_unused(id); + + return sub; } -void DXFeedSubscription::removeSymbolsImpl(void *graalSymbolList) const noexcept { - if (!handle_) { - return; +std::shared_ptr DXFeedSubscription::create(std::initializer_list eventTypes) { + auto sub = createShared(eventTypes); + auto id = ApiContext::getInstance()->getManager()->registerEntity(sub); + + dxfcpp::ignore_unused(id); + + return sub; +} + +void DXFeedSubscription::attach(std::shared_ptr feed) { + if constexpr (Debugger::isDebug) { + Debugger::debug(toString() + "::attach(feed = " + feed->toString() + ")"); } - runIsolatedOrElse( - [handle = static_cast(handle_.get()), graalSymbolList](auto threadHandle) { - return dxfg_DXFeedSubscription_removeSymbols(static_cast(threadHandle), handle, - static_cast(graalSymbolList)) == 0; - }, - false); + feed->attachSubscription(sharedAs()); } -void DXFeedSubscription::setSymbolsImpl(void *graalSymbolList) const noexcept { - if (!handle_) { - return; +void DXFeedSubscription::detach(std::shared_ptr feed) { + if constexpr (Debugger::isDebug) { + Debugger::debug(toString() + "::detach(feed = " + feed->toString() + ")"); } - runIsolatedOrElse( - [handle = static_cast(handle_.get()), graalSymbolList](auto threadHandle) { - return dxfg_DXFeedSubscription_setSymbols(static_cast(threadHandle), handle, - static_cast(graalSymbolList)) == 0; - }, - false); + feed->detachSubscription(sharedAs()); } -std::vector DXFeedSubscription::getSymbolsImpl() const { - if (!handle_) { - return {}; +void DXFeedSubscription::close() const { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug(toString() + "::close()"); } - dxfg_symbol_list *list = runIsolatedOrElse( - [handle = static_cast(handle_.get())](auto threadHandle) { - return dxfg_DXFeedSubscription_getSymbols(static_cast(threadHandle), handle); - }, - nullptr); + isolated::api::IsolatedDXFeedSubscription::close(handle_); +} + +void DXFeedSubscription::removeEventListener(std::size_t listenerId) { + onEvent_ -= listenerId; +} + +DXFeedSubscription::OnEventHandler &DXFeedSubscription::onEvent() { + tryToSetEventListenerHandle(); + + return onEvent_; +} - auto result = SymbolWrapper::SymbolListUtils::fromGraalList(static_cast(list)); +void DXFeedSubscription::addSymbols(const SymbolWrapper &symbolWrapper) const { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug(toString() + "::addSymbols(symbolWrapper = " + toStringAny(symbolWrapper) + ")"); + } - runIsolatedOrElse( - [list](auto threadHandle) { - return dxfg_CList_symbol_release(static_cast(threadHandle), list) == 0; - }, - false); + auto graal = symbolWrapper.toGraalUnique(); - return result; + isolated::api::IsolatedDXFeedSubscription::addSymbol(handle_, graal.get()); } -std::vector DXFeedSubscription::getDecoratedSymbolsImpl() const { - if (!handle_) { - return {}; +void DXFeedSubscription::removeSymbols(const SymbolWrapper &symbolWrapper) const { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug(toString() + "::removeSymbols(symbolWrapper = " + toStringAny(symbolWrapper) + ")"); } - dxfg_symbol_list *list = runIsolatedOrElse( - [handle = static_cast(handle_.get())](auto threadHandle) { - return dxfg_DXFeedSubscription_getDecoratedSymbols(static_cast(threadHandle), - handle); - }, - nullptr); + auto graal = symbolWrapper.toGraalUnique(); - auto result = SymbolWrapper::SymbolListUtils::fromGraalList(static_cast(list)); + isolated::api::IsolatedDXFeedSubscription::removeSymbol(handle_, graal.get()); +} - runIsolatedOrElse( - [list](auto threadHandle) { - return dxfg_CList_symbol_release(static_cast(threadHandle), list) == 0; - }, - false); +void DXFeedSubscription::addSymbols(std::initializer_list collection) const { + addSymbols(collection.begin(), collection.end()); +} - return result; +void DXFeedSubscription::removeSymbols(std::initializer_list collection) const { + removeSymbols(collection.begin(), collection.end()); } -void DXFeedSubscription::closeImpl() const noexcept { - if (!handle_) { - return; +void DXFeedSubscription::setSymbols(std::initializer_list collection) const { + setSymbols(collection.begin(), collection.end()); +} + +void DXFeedSubscription::clear() const { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug(toString() + "::clear()"); } - runIsolatedOrElse( - [handle = static_cast(handle_.get())](auto threadHandle) { - return dxfg_DXFeedSubscription_close(static_cast(threadHandle), handle) == 0; - }, - false); + isolated::api::IsolatedDXFeedSubscription::clear(handle_); } -void DXFeedSubscription::clearImpl() const noexcept { - if (!handle_) { - return; +bool DXFeedSubscription::isClosed() { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug(toString() + "::isClosed()"); } - runIsolatedOrElse( - [handle = static_cast(handle_.get())](auto threadHandle) { - return dxfg_DXFeedSubscription_clear(static_cast(threadHandle), handle) == 0; - }, - false); + return isolated::api::IsolatedDXFeedSubscription::isClosed(handle_); } -bool DXFeedSubscription::isClosedImpl() const noexcept { - if (!handle_) { - return false; - } +std::unordered_set DXFeedSubscription::getEventTypes() { + return eventTypes_; +} - return runIsolatedOrElse( - [handle = static_cast(handle_.get())](auto threadHandle) { - return dxfg_DXFeedSubscription_isClosed(static_cast(threadHandle), handle) != 0; - }, - false); +bool DXFeedSubscription::containsEventType(const EventTypeEnum &eventType) { + return eventTypes_.contains(eventType); } -DXFeedSubscription::DXFeedSubscription(const EventTypeEnum &eventType) - : eventTypes_{eventType}, handle_{}, eventListenerHandle_{}, onEvent_{} { +std::vector DXFeedSubscription::getSymbols() const { if constexpr (Debugger::isDebug) { - Debugger::debug("DXFeedSubscription(eventType = " + eventType.getName() + ")"); + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug(toString() + "::getSymbols()"); } - handle_ = JavaObjectHandle(runIsolatedOrElse( - [eventType](auto threadHandle) { - return dxfg_DXFeedSubscription_new(static_cast(threadHandle), - static_cast(eventType.getId())); - }, - nullptr)); + return isolated::api::IsolatedDXFeedSubscription::getSymbols(handle_); } -JavaObjectHandle -DXFeedSubscription::createSubscriptionHandleFromEventClassList(const std::unique_ptr &list) { - if (!list) { - throw std::invalid_argument("EventClassList is nullptr"); +std::vector DXFeedSubscription::getDecoratedSymbols() const { + if constexpr (Debugger::isDebug) { + // ReSharper disable once CppDFAUnreachableCode + Debugger::debug(toString() + "::getDecoratedSymbols()"); } - return JavaObjectHandle(runIsolatedOrElse( - [listHandle = static_cast(list->getHandle())](auto threadHandle) { - return dxfg_DXFeedSubscription_new2(static_cast(threadHandle), listHandle); - }, - nullptr)); + return isolated::api::IsolatedDXFeedSubscription::getDecoratedSymbols(handle_); } -void DXFeedSubscription::setEventListenerHandle(Id id) { - auto onEvents = [](graal_isolatethread_t * /*thread*/, dxfg_event_type_list *graalNativeEvents, void *userData) { - auto id = Id::from(dxfcpp::bit_cast::ValueType>(userData)); - auto sub = ApiContext::getInstance()->getManager()->getEntity(id); +std::size_t DXFeedSubscription::addChangeListener(std::shared_ptr listener) { + isolated::api::IsolatedDXFeedSubscription::addChangeListener(handle_, listener->getHandle()); - if (sub) { - auto &&events = EventMapper::fromGraalList(static_cast(graalNativeEvents)); + std::lock_guard guard{changeListenersMutex_}; - sub->onEvent_(events); - } - }; - - eventListenerHandle_ = JavaObjectHandle(runIsolatedOrElse( - [idValue = id.getValue(), onEvents](auto threadHandle) { - return dxfg_DXFeedEventListener_new(static_cast(threadHandle), onEvents, - dxfcpp::bit_cast(idValue)); - }, - nullptr)); - - if (handle_ && eventListenerHandle_) { - runIsolatedOrElse( - [handle = static_cast(handle_.get()), - eventListenerHandle = - static_cast(eventListenerHandle_.get())](auto threadHandle) { - return dxfg_DXFeedSubscription_addEventListener(static_cast(threadHandle), - handle, eventListenerHandle) == 0; - }, - false); + if (lastChangeListenerId_ >= FAKE_CHANGE_LISTENER_ID - 1) { + return FAKE_CHANGE_LISTENER_ID; } -} -bool DXFeedSubscription::tryToSetEventListenerHandle() noexcept { - std::lock_guard lock{listenerMutex_}; + auto id = ++lastChangeListenerId_; - if (!eventListenerHandle_) { - auto idOpt = - ApiContext::getInstance()->getManager()->getId(sharedAs()); + changeListeners_.emplace(id, listener); - if (!idOpt) { - return false; - } + return id; +} - setEventListenerHandle(idOpt.value()); +void DXFeedSubscription::removeChangeListener(std::size_t changeListenerId) { + std::lock_guard guard{changeListenersMutex_}; + + if (changeListenerId == FAKE_CHANGE_LISTENER_ID) { + return; } - return true; -} + if (auto found = changeListeners_.find(changeListenerId); found != changeListeners_.end()) { + auto listener = found->second; -std::string DXFeedSubscription::toString() const noexcept { - return fmt::format("DXFeedSubscription{{{}}}", handle_.toString()); + isolated::api::IsolatedDXFeedSubscription::removeChangeListener(handle_, listener->getHandle()); + + changeListeners_.erase(found); + } } DXFCPP_END_NAMESPACE \ No newline at end of file diff --git a/src/api/DXPublisherObservableSubscription.cpp b/src/api/DXPublisherObservableSubscription.cpp index 77b2b972c..b1abfd70a 100644 --- a/src/api/DXPublisherObservableSubscription.cpp +++ b/src/api/DXPublisherObservableSubscription.cpp @@ -52,14 +52,14 @@ DXPublisherObservableSubscription::addChangeListener(std::shared_ptrsecond; isolated::api::IsolatedDXPublisherObservableSubscription::removeChangeListener(handle_, listener->getHandle()); diff --git a/src/event/EventMapper.cpp b/src/event/EventMapper.cpp index f0dc7a486..32add654a 100644 --- a/src/event/EventMapper.cpp +++ b/src/event/EventMapper.cpp @@ -16,6 +16,58 @@ DXFCPP_BEGIN_NAMESPACE +std::shared_ptr EventMapper::fromGraal(void *graalNativeEvent) { + if (!graalNativeEvent) { + throw std::invalid_argument("The `graalNativeEvent` is nullptr"); + } + + // TODO: implement other types [EN-8235] + switch (auto *e = dxfcpp::bit_cast(graalNativeEvent); e->clazz) { + case DXFG_EVENT_QUOTE: + return Quote::fromGraal(e); + case DXFG_EVENT_PROFILE: + return Profile::fromGraal(e); + case DXFG_EVENT_SUMMARY: + return Summary::fromGraal(e); + case DXFG_EVENT_GREEKS: + return Greeks::fromGraal(e); + case DXFG_EVENT_CANDLE: + return Candle::fromGraal(e); + case DXFG_EVENT_DAILY_CANDLE: + throw std::invalid_argument("Not emplemented event type: " + std::to_string(static_cast(e->clazz))); + case DXFG_EVENT_UNDERLYING: + return Underlying::fromGraal(e); + case DXFG_EVENT_THEO_PRICE: + return TheoPrice::fromGraal(e); + case DXFG_EVENT_TRADE: + return Trade::fromGraal(e); + case DXFG_EVENT_TRADE_ETH: + return TradeETH::fromGraal(e); + case DXFG_EVENT_CONFIGURATION: + throw std::invalid_argument("Not emplemented event type: " + std::to_string(static_cast(e->clazz))); + case DXFG_EVENT_MESSAGE: + return Message::fromGraal(e); + case DXFG_EVENT_TIME_AND_SALE: + return TimeAndSale::fromGraal(e); + case DXFG_EVENT_ORDER_BASE: + throw std::invalid_argument("Not emplemented event type: " + std::to_string(static_cast(e->clazz))); + case DXFG_EVENT_ORDER: + return Order::fromGraal(e); + case DXFG_EVENT_ANALYTIC_ORDER: + return AnalyticOrder::fromGraal(e); + case DXFG_EVENT_OTC_MARKETS_ORDER: + return OtcMarketsOrder::fromGraal(e); + case DXFG_EVENT_SPREAD_ORDER: + return SpreadOrder::fromGraal(e); + case DXFG_EVENT_SERIES: + return Series::fromGraal(e); + case DXFG_EVENT_OPTION_SALE: + return OptionSale::fromGraal(e); + default: + throw std::invalid_argument("Unknown event type: " + std::to_string(static_cast(e->clazz))); + } +} + std::vector> EventMapper::fromGraalList(void *graalNativeList) { auto list = static_cast(graalNativeList); @@ -27,89 +79,7 @@ std::vector> EventMapper::fromGraalList(void *graalNa result.reserve(static_cast(list->size)); for (std::size_t i = 0; i < static_cast(list->size); i++) { - auto *e = list->elements[i]; - - // TODO: implement other types [EN-8235] - // TODO: type traits - switch (e->clazz) { - case DXFG_EVENT_QUOTE: - result.emplace_back(Quote::fromGraal(e)); - - break; - case DXFG_EVENT_PROFILE: - result.emplace_back(Profile::fromGraal(e)); - - break; - case DXFG_EVENT_SUMMARY: - result.emplace_back(Summary::fromGraal(e)); - - break; - case DXFG_EVENT_GREEKS: - result.emplace_back(Greeks::fromGraal(e)); - - break; - case DXFG_EVENT_CANDLE: - result.emplace_back(Candle::fromGraal(e)); - - break; - case DXFG_EVENT_DAILY_CANDLE: - break; - case DXFG_EVENT_UNDERLYING: - result.emplace_back(Underlying::fromGraal(e)); - - break; - case DXFG_EVENT_THEO_PRICE: - result.emplace_back(TheoPrice::fromGraal(e)); - - break; - case DXFG_EVENT_TRADE: - result.emplace_back(Trade::fromGraal(e)); - - break; - case DXFG_EVENT_TRADE_ETH: - result.emplace_back(TradeETH::fromGraal(e)); - - break; - case DXFG_EVENT_CONFIGURATION: - break; - case DXFG_EVENT_MESSAGE: - result.emplace_back(Message::fromGraal(e)); - - break; - case DXFG_EVENT_TIME_AND_SALE: - result.emplace_back(TimeAndSale::fromGraal(e)); - - break; - case DXFG_EVENT_ORDER_BASE: - break; - case DXFG_EVENT_ORDER: - result.emplace_back(Order::fromGraal(e)); - - break; - case DXFG_EVENT_ANALYTIC_ORDER: - result.emplace_back(AnalyticOrder::fromGraal(e)); - - break; - case DXFG_EVENT_OTC_MARKETS_ORDER: - result.emplace_back(OtcMarketsOrder::fromGraal(e)); - - break; - case DXFG_EVENT_SPREAD_ORDER: - result.emplace_back(SpreadOrder::fromGraal(e)); - - break; - case DXFG_EVENT_SERIES: - result.emplace_back(Series::fromGraal(e)); - - break; - case DXFG_EVENT_OPTION_SALE: - result.emplace_back(OptionSale::fromGraal(e)); - - break; - - default: - throw std::invalid_argument("Unknown event type: " + std::to_string(static_cast(e->clazz))); - } + result.emplace_back(fromGraal(list->elements[i])); } result.shrink_to_fit(); @@ -117,6 +87,95 @@ std::vector> EventMapper::fromGraalList(void *graalNa return result; } +void EventMapper::freeGraal(void *graalNativeEvent) { + if (!graalNativeEvent) { + return; + } + + // TODO: implement other types [EN-8235] + switch (auto *e = dxfcpp::bit_cast(graalNativeEvent); e->clazz) { + case DXFG_EVENT_QUOTE: + Quote::freeGraal(e); + + break; + case DXFG_EVENT_PROFILE: + Profile::freeGraal(e); + + break; + case DXFG_EVENT_SUMMARY: + Summary::freeGraal(e); + + break; + case DXFG_EVENT_GREEKS: + Greeks::freeGraal(e); + + break; + case DXFG_EVENT_CANDLE: + Candle::freeGraal(e); + + break; + case DXFG_EVENT_DAILY_CANDLE: + throw std::invalid_argument("Not emplemented event type: " + std::to_string(static_cast(e->clazz))); + + case DXFG_EVENT_UNDERLYING: + Underlying::freeGraal(e); + + break; + case DXFG_EVENT_THEO_PRICE: + TheoPrice::freeGraal(e); + + break; + case DXFG_EVENT_TRADE: + Trade::freeGraal(e); + + break; + case DXFG_EVENT_TRADE_ETH: + TradeETH::freeGraal(e); + + break; + case DXFG_EVENT_CONFIGURATION: + throw std::invalid_argument("Not emplemented event type: " + std::to_string(static_cast(e->clazz))); + + case DXFG_EVENT_MESSAGE: + Message::freeGraal(e); + + break; + case DXFG_EVENT_TIME_AND_SALE: + TimeAndSale::freeGraal(e); + + break; + case DXFG_EVENT_ORDER_BASE: + throw std::invalid_argument("Not emplemented event type: " + std::to_string(static_cast(e->clazz))); + + case DXFG_EVENT_ORDER: + Order::freeGraal(e); + + break; + case DXFG_EVENT_ANALYTIC_ORDER: + AnalyticOrder::freeGraal(e); + + break; + case DXFG_EVENT_OTC_MARKETS_ORDER: + OtcMarketsOrder::freeGraal(e); + + break; + case DXFG_EVENT_SPREAD_ORDER: + SpreadOrder::freeGraal(e); + + break; + case DXFG_EVENT_SERIES: + Series::freeGraal(e); + + break; + case DXFG_EVENT_OPTION_SALE: + OptionSale::freeGraal(e); + + break; + default: + throw std::invalid_argument("Unknown event type: " + std::to_string(static_cast(e->clazz))); + } +} + void EventMapper::freeGraalList(void *graalList) { if constexpr (Debugger::isDebug) { Debugger::debug("EventMapper::freeGraalList(graalList = " + toStringAny(graalList) + ")"); @@ -133,90 +192,7 @@ void EventMapper::freeGraalList(void *graalList) { if (list->size > 0 && list->elements != nullptr) { for (SizeType elementIndex = 0; elementIndex < list->size; elementIndex++) { - if (list->elements[elementIndex]) { - auto *e = list->elements[elementIndex]; - - // TODO: implement other types [EN-8235] - // TODO: type traits - switch (e->clazz) { - case DXFG_EVENT_QUOTE: - Quote::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_PROFILE: - Profile::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_SUMMARY: - Summary::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_GREEKS: - Greeks::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_CANDLE: - Candle::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_DAILY_CANDLE: - break; - case DXFG_EVENT_UNDERLYING: - Underlying::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_THEO_PRICE: - TheoPrice::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_TRADE: - Trade::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_TRADE_ETH: - TradeETH::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_CONFIGURATION: - break; - case DXFG_EVENT_MESSAGE: - Message::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_TIME_AND_SALE: - TimeAndSale::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_ORDER_BASE: - break; - case DXFG_EVENT_ORDER: - Order::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_ANALYTIC_ORDER: - AnalyticOrder::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_OTC_MARKETS_ORDER: - OtcMarketsOrder::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_SPREAD_ORDER: - SpreadOrder::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_SERIES: - Series::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_OPTION_SALE: - OptionSale::freeGraal(static_cast(e)); - - break; - default: - throw std::invalid_argument("Unknown event type: " + std::to_string(static_cast(e->clazz))); - } - } + freeGraal(list->elements[elementIndex]); } delete[] list->elements; @@ -231,7 +207,9 @@ std::ptrdiff_t EventMapper::calculateGraalListSize(std::ptrdiff_t initSize) noex if (initSize < 0) { return 0; - } else if (initSize > std::numeric_limits::max()) { + } + + if (initSize > std::numeric_limits::max()) { return std::numeric_limits::max(); } @@ -282,91 +260,7 @@ bool EventMapper::freeGraalListElements(void *graalList, std::ptrdiff_t count) { auto *list = static_cast(graalList); for (SizeType i = 0; i < count; i++) { - if (list->elements[i]) { - auto *e = list->elements[i]; - - // TODO: implement other types [EN-8235] - // TODO: type traits - switch (e->clazz) { - case DXFG_EVENT_QUOTE: - Quote::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_PROFILE: - Profile::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_SUMMARY: - Summary::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_GREEKS: - Greeks::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_CANDLE: - Candle::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_DAILY_CANDLE: - break; - case DXFG_EVENT_UNDERLYING: - Underlying::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_THEO_PRICE: - TheoPrice::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_TRADE: - Trade::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_TRADE_ETH: - TradeETH::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_CONFIGURATION: - break; - case DXFG_EVENT_MESSAGE: - Message::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_TIME_AND_SALE: - TimeAndSale::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_ORDER_BASE: - break; - case DXFG_EVENT_ORDER: - Order::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_ANALYTIC_ORDER: - AnalyticOrder::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_OTC_MARKETS_ORDER: - OtcMarketsOrder::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_SPREAD_ORDER: - SpreadOrder::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_SERIES: - Series::freeGraal(static_cast(e)); - - break; - case DXFG_EVENT_OPTION_SALE: - OptionSale::freeGraal(static_cast(e)); - - break; - - default: - throw std::invalid_argument("Unknown event type: " + std::to_string(static_cast(e->clazz))); - } - } + freeGraal(list->elements[i]); } delete[] list->elements; diff --git a/src/exceptions/JavaException.cpp b/src/exceptions/JavaException.cpp index 6988fb8b1..b3ee9a5a8 100644 --- a/src/exceptions/JavaException.cpp +++ b/src/exceptions/JavaException.cpp @@ -19,9 +19,7 @@ void JavaException::throwIfJavaThreadExceptionExists() { return; } - auto message = toString(exception->message); - auto className = toString(exception->class_name); - auto stackTrace = toString(exception->print_stack_trace); + auto javaException = create(exception); runIsolatedThrow( [](auto threadHandle, auto &&...params) { @@ -29,7 +27,7 @@ void JavaException::throwIfJavaThreadExceptionExists() { }, exception); - throw JavaException(message, className, stackTrace); + throw javaException; // NOLINT(*-throw-by-value-catch-by-reference) } void JavaException::throwException() { @@ -98,6 +96,16 @@ JavaException::JavaException(const std::string &message, const std::string &clas stackTrace_{std::move(stackTrace) + "\n" + stackTraceToString(boost::stacktrace::stacktrace())} { } +JavaException JavaException::create(void *exceptionHandle) { + if (exceptionHandle == nullptr) { + return {"null", "", ""}; + } + + auto *exception = dxfcpp::bit_cast(exceptionHandle); + + return {toString(exception->message), toString(exception->class_name), toString(exception->print_stack_trace)}; +} + const std::string &JavaException::getStackTrace() const & { return stackTrace_; } diff --git a/src/internal/JavaObjectHandle.cpp b/src/internal/JavaObjectHandle.cpp index 21893ddc0..d45ac45a6 100644 --- a/src/internal/JavaObjectHandle.cpp +++ b/src/internal/JavaObjectHandle.cpp @@ -26,7 +26,31 @@ template void JavaObjectHandle::deleter(void *handle) noexcept { dxfcpp::ignore_unused(result); if constexpr (Debugger::isDebug) { - Debugger::debug(getDebugName() + "::deleter(handle = " + dxfcpp::toString(handle) + ") -> " + dxfcpp::toString(result)); + Debugger::debug(getDebugName() + "::deleter(handle = " + dxfcpp::toString(handle) + ") -> " + + dxfcpp::toString(result)); + } +} + +template void JavaObjectHandleList::deleter(void *handle) noexcept { + auto result = runIsolatedOrElse( + [handle = handle](auto threadHandle) { + if constexpr (Debugger::isDebug) { + Debugger::debug(getDebugName() + "::deleter(handle = " + dxfcpp::toString(handle) + ")"); + } + + if (handle) { + return dxfg_CList_JavaObjectHandler_release(static_cast(threadHandle), + static_cast(handle)) == 0; + } + + return true; + }, + false); + dxfcpp::ignore_unused(result); + + if constexpr (Debugger::isDebug) { + Debugger::debug(getDebugName() + "::deleter(handle = " + dxfcpp::toString(handle) + ") -> " + + dxfcpp::toString(result)); } } @@ -59,4 +83,8 @@ template struct JavaObjectHandle; template struct JavaObjectHandle; template struct JavaObjectHandle; +template struct JavaObjectHandle; +template struct JavaObjectHandle; +template struct JavaObjectHandle; + DXFCPP_END_NAMESPACE \ No newline at end of file diff --git a/src/isolated/api/IsolatedDXFeed.cpp b/src/isolated/api/IsolatedDXFeed.cpp new file mode 100644 index 000000000..1358bd752 --- /dev/null +++ b/src/isolated/api/IsolatedDXFeed.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include +#include + +DXFCPP_BEGIN_NAMESPACE + +namespace isolated::api::IsolatedDXFeed { + +/* dxfg_promise_events_t* */ void *getTimeSeriesPromise(/* dxfg_feed_t * */ const JavaObjectHandle &feed, + /* dxfg_event_clazz_t */ const EventTypeEnum &eventType, + /* dxfg_symbol_t * */ const SymbolWrapper &symbol, + std::int64_t fromTime, std::int64_t toTime) { + if (!feed) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeed_getTimeSeriesPromise`. The `feed` handle is invalid"); + } + + auto graalSymbol = symbol.toGraal(); + + auto result = dxfcpp::bit_cast( + runGraalFunctionAndThrowIfNullptr(dxfg_DXFeed_getTimeSeriesPromise, static_cast(feed.get()), + static_cast(eventType.getId()), + static_cast(graalSymbol), fromTime, toTime)); + + SymbolWrapper::freeGraal(graalSymbol); + + return result; +} + +} // namespace isolated::api::IsolatedDXFeed + +DXFCPP_END_NAMESPACE \ No newline at end of file diff --git a/src/isolated/api/IsolatedDXFeedSubscription.cpp b/src/isolated/api/IsolatedDXFeedSubscription.cpp new file mode 100644 index 000000000..a76c818d4 --- /dev/null +++ b/src/isolated/api/IsolatedDXFeedSubscription.cpp @@ -0,0 +1,247 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include +#include + +DXFCPP_BEGIN_NAMESPACE + +namespace isolated::api::IsolatedDXFeedSubscription { + +JavaObjectHandle /* dxfg_subscription_t* */ +create(/* dxfg_event_clazz_t */ const EventTypeEnum &eventType) { + return JavaObjectHandle(runGraalFunctionAndThrowIfNullptr( + dxfg_DXFeedSubscription_new, dxfcpp::bit_cast(eventType.getId()))); +} + +JavaObjectHandle /* dxfg_subscription_t* */ +create(/* dxfg_event_clazz_list_t * */ const std::unique_ptr &eventClassList) { + if (!eventClassList) { + throw std::invalid_argument("The eventClassList is nullptr"); + } + + return JavaObjectHandle(runGraalFunctionAndThrowIfNullptr( + dxfg_DXFeedSubscription_new2, static_cast(eventClassList->getHandle()))); +} + +void /* int32_t */ close(/* dxfg_subscription_t * */ const JavaObjectHandle &sub) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_close`. The `sub` handle is invalid"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_close, + static_cast(sub.get())); +} + +void /* int32_t */ +addEventListener(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_feed_event_listener_t * */ const JavaObjectHandle &listener) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_addEventListener`. The `sub` handle is invalid"); + } + + if (!listener) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_addEventListener`. The " + "`listener` handle is invalid"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_addEventListener, + static_cast(sub.get()), + static_cast(listener.get())); +} + +void /* int32_t */ addSymbol(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_t * */ void *symbol) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_addSymbol`. The `sub` handle is invalid"); + } + + if (!symbol) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_addSymbol`. The " + "`symbol` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_addSymbol, + static_cast(sub.get()), + static_cast(symbol)); +} + +void /* int32_t */ addSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_list * */ void *symbols) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_addSymbols`. The `sub` handle is invalid"); + } + + if (!symbols) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_addSymbols`. The " + "`symbols` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_addSymbols, + static_cast(sub.get()), + static_cast(symbols)); +} + +void /* int32_t */ removeSymbol(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_t * */ void *symbol) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_removeSymbol`. The `sub` handle is invalid"); + } + + if (!symbol) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_removeSymbol`. The " + "`symbol` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_removeSymbol, + static_cast(sub.get()), + static_cast(symbol)); +} + +void /* int32_t */ removeSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_symbol_list * */ void *symbols) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_removeSymbols`. The `sub` handle is invalid"); + } + + if (!symbols) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_removeSymbols`. The " + "`symbols` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_removeSymbols, + static_cast(sub.get()), + static_cast(symbols)); +} + +void /* int32_t */ clear(/* dxfg_subscription_t * */ const JavaObjectHandle &sub) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_clear`. The `sub` handle is invalid"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_clear, + static_cast(sub.get())); +} + +bool /* int32_t */ isClosed(/* dxfg_subscription_t * */ const JavaObjectHandle &sub) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_isClosed`. The `sub` handle is invalid"); + } + + return runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_isClosed, + static_cast(sub.get())) == 1; +} + +std::vector /* dxfg_symbol_list* */ getSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_getSymbols`. The `sub` handle is invalid"); + } + + dxfg_symbol_list *list = runGraalFunctionAndThrowIfNullptr( + dxfg_DXFeedSubscription_getSymbols, static_cast(sub.get())); + + auto result = SymbolWrapper::SymbolListUtils::fromGraalList(static_cast(list)); + + runGraalFunctionAndThrowIfLessThanZero(dxfg_CList_symbol_release, list); + + return result; +} + +void /* int32_t */ setSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub, /* dxfg_symbol_list * */ void* symbols) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_setSymbols`. The `sub` handle is invalid"); + } + + if (!symbols) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_setSymbols`. The " + "`symbols` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_DXFeedSubscription_setSymbols, + static_cast(sub.get()), + static_cast(symbols)); +} + +std::vector /* dxfg_symbol_list* */ getDecoratedSymbols(/* dxfg_subscription_t * */ const JavaObjectHandle &sub) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_getDecoratedSymbols`. The `sub` handle is invalid"); + } + + dxfg_symbol_list *list = runGraalFunctionAndThrowIfNullptr( + dxfg_DXFeedSubscription_getDecoratedSymbols, static_cast(sub.get())); + + auto result = SymbolWrapper::SymbolListUtils::fromGraalList(static_cast(list)); + + runGraalFunctionAndThrowIfLessThanZero(dxfg_CList_symbol_release, list); + + return result; +} + +void /* int32_t */ addChangeListener( + /* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_observable_subscription_change_listener_t * */ const JavaObjectHandle + &listener) { + if (!sub) { + throw std::invalid_argument( + "Unable to execute function `dxfg_DXFeedSubscription_addChangeListener`. The `sub` handle is invalid"); + } + + if (!listener) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_addChangeListener`. The " + "`listener` handle is invalid"); + } + + runGraalFunctionAndThrowIfLessThanZero( + dxfg_DXFeedSubscription_addChangeListener, static_cast(sub.get()), + static_cast(listener.get())); +} + +void /* int32_t */ removeChangeListener( + /* dxfg_subscription_t * */ const JavaObjectHandle &sub, + /* dxfg_observable_subscription_change_listener_t * */ const JavaObjectHandle + &listener) { + if (!sub) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_removeChangeListener`. " + "The `sub` handle is invalid"); + } + + if (!listener) { + throw std::invalid_argument("Unable to execute function `dxfg_DXFeedSubscription_removeChangeListener`. The " + "`listener` handle is invalid"); + } + + runGraalFunctionAndThrowIfLessThanZero( + dxfg_DXFeedSubscription_removeChangeListener, static_cast(sub.get()), + static_cast(listener.get())); +} + +namespace DXFeedEventListener { + +JavaObjectHandle /* dxfg_feed_event_listener_t* */ +create(/* dxfg_feed_event_listener_function */ void *userFunc, void *userData) { + if (!userFunc) { + throw std::invalid_argument("Unable to create DXFeedEventListener. The `userFunc` parameter is nullptr"); + } + + return JavaObjectHandle(runGraalFunctionAndThrowIfNullptr( + dxfg_DXFeedEventListener_new, dxfcpp::bit_cast(userFunc), userData)); +} + +} // namespace DXFeedEventListener + +} // namespace isolated::api::IsolatedDXFeedSubscription + +DXFCPP_END_NAMESPACE diff --git a/src/isolated/promise/IsolatedPromise.cpp b/src/isolated/promise/IsolatedPromise.cpp new file mode 100644 index 000000000..b88776ab2 --- /dev/null +++ b/src/isolated/promise/IsolatedPromise.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include +#include +#include + +DXFCPP_BEGIN_NAMESPACE + +namespace isolated::promise::IsolatedPromise { + +bool /* int32_t */ isDone(/* dxfg_promise_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_isDone`. The `promise` is nullptr"); + } + + return runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_isDone, static_cast(promise)) == 1; +} + +bool /* int32_t */ hasResult(/* dxfg_promise_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_hasResult`. The `promise` is nullptr"); + } + + return runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_hasResult, static_cast(promise)) == 1; +} + +bool /* int32_t */ hasException(/* dxfg_promise_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_hasException`. The `promise` is nullptr"); + } + + return runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_hasException, static_cast(promise)) == + 1; +} + +bool /* int32_t */ isCancelled(/* dxfg_promise_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_isCancelled`. The `promise` is nullptr"); + } + + return runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_isCancelled, static_cast(promise)) == + 1; +} + +std::shared_ptr /* dxfg_event_type_t* */ getResult(/* dxfg_promise_event_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument( + "Unable to execute function `dxfg_Promise_EventType_getResult`. The `promise` is nullptr"); + } + + auto *graalEvent = runGraalFunctionAndThrowIfNullptr(dxfg_Promise_EventType_getResult, + static_cast(promise)); + + auto result = dxfcpp::EventMapper::fromGraal(graalEvent); + + runGraalFunctionAndThrowIfLessThanZero(dxfg_EventType_release, graalEvent); + + return result; +} + +std::vector> /* dxfg_event_type_list* */ +getResults(/* dxfg_promise_events_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument( + "Unable to execute function `dxfg_Promise_List_EventType_getResult`. The `promise` is nullptr"); + } + + auto *graalEvents = runGraalFunctionAndThrowIfNullptr(dxfg_Promise_List_EventType_getResult, + static_cast(promise)); + + auto result = dxfcpp::EventMapper::fromGraalList(graalEvents); + + runGraalFunctionAndThrowIfLessThanZero(dxfg_CList_EventType_release, graalEvents); + + return result; +} + +JavaException /* dxfg_exception_t* */ getException(/* dxfg_promise_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_getException`. The `promise` is nullptr"); + } + + auto *graalException = + runGraalFunctionAndThrowIfNullptr(dxfg_Promise_getException, static_cast(promise)); + + auto result = JavaException::create(graalException); + + runGraalFunction(dxfg_Exception_release, graalException); + + return result; +} + +void /* int32_t */ await(/* dxfg_promise_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_await`. The `promise` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_await, static_cast(promise)); +} + +void /* int32_t */ await(/* dxfg_promise_t * */ void *promise, std::int32_t timeoutInMilliseconds) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_await2`. The `promise` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_await2, static_cast(promise), + timeoutInMilliseconds); +} + +bool /* int32_t */ awaitWithoutException(/* dxfg_promise_t * */ void *promise, std::int32_t timeoutInMilliseconds) { + if (!promise) { + throw std::invalid_argument( + "Unable to execute function `dxfg_Promise_awaitWithoutException`. The `promise` is nullptr"); + } + + return runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_awaitWithoutException, + static_cast(promise), timeoutInMilliseconds) == 1; +} + +void /* int32_t */ cancel(/* dxfg_promise_t * */ void *promise) { + if (!promise) { + throw std::invalid_argument("Unable to execute function `dxfg_Promise_cancel`. The `promise` is nullptr"); + } + + runGraalFunctionAndThrowIfLessThanZero(dxfg_Promise_cancel, static_cast(promise)); +} + +} // namespace isolated::promise::IsolatedPromise + +DXFCPP_END_NAMESPACE diff --git a/src/promise/Promise.cpp b/src/promise/Promise.cpp new file mode 100644 index 000000000..f36d0ef72 --- /dev/null +++ b/src/promise/Promise.cpp @@ -0,0 +1,80 @@ +// Copyright (c) 2024 Devexperts LLC. +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +DXFCPP_BEGIN_NAMESPACE + +PromiseImpl::PromiseImpl(void *handle) : handle(handle) { +} + +bool PromiseImpl::isDone() const { + return isolated::promise::IsolatedPromise::isDone(handle); +} + +bool PromiseImpl::hasResult() const { + return isolated::promise::IsolatedPromise::hasResult(handle); +} + +bool PromiseImpl::hasException() const { + return isolated::promise::IsolatedPromise::hasException(handle); +} + +bool PromiseImpl::isCancelled() const { + return isolated::promise::IsolatedPromise::isCancelled(handle); +} + +JavaException PromiseImpl::getException() const { + return isolated::promise::IsolatedPromise::getException(handle); +} + +void PromiseImpl::await() const { + isolated::promise::IsolatedPromise::await(handle); +} + +void PromiseImpl::await(std::int32_t timeoutInMilliseconds) const { + isolated::promise::IsolatedPromise::await(handle, timeoutInMilliseconds); +} + +bool PromiseImpl::awaitWithoutException(std::int32_t timeoutInMilliseconds) const { + return isolated::promise::IsolatedPromise::awaitWithoutException(handle, timeoutInMilliseconds); +} + +void PromiseImpl::cancel() const { + isolated::promise::IsolatedPromise::cancel(handle); +} + +EventPromiseImpl::EventPromiseImpl(void *handle) : PromiseImpl(handle), handle(handle) { +} + +EventPromiseImpl::~EventPromiseImpl() { + JavaObjectHandle::deleter(handle); +} + +std::shared_ptr EventPromiseImpl::getResult() const { + return isolated::promise::IsolatedPromise::getResult(handle); +} + +EventsPromiseImpl::EventsPromiseImpl(void *handle) : PromiseImpl(handle), handle(handle) { +} + +EventsPromiseImpl::~EventsPromiseImpl() { + JavaObjectHandle::deleter(handle); +} + +std::vector> EventsPromiseImpl::getResult() const { + return isolated::promise::IsolatedPromise::getResults(handle); +} + +DXFCPP_END_NAMESPACE \ No newline at end of file diff --git a/tools/Tools/src/main.cpp b/tools/Tools/src/main.cpp index b90cd72df..70661a07c 100644 --- a/tools/Tools/src/main.cpp +++ b/tools/Tools/src/main.cpp @@ -28,6 +28,12 @@ using namespace dxfcpp::literals; int main(int argc, char *argv[]) { try { + System::setProperty(DXEndpoint::DXFEED_WILDCARD_ENABLE_PROPERTY, "true"); + // Enable experimental feature. + System::setProperty("dxfeed.experimental.dxlink.enable", "true"); + // Set scheme for dxLink. + System::setProperty("scheme", "ext:opt:sysprops,resource:dxlink.xml"); + const auto usage = tools::HelpTool::generateToolHelpScreen(); std::vector args{}; @@ -97,7 +103,7 @@ int main(int argc, char *argv[]) { } catch (const GraalException &e) { std::cerr << e.what() << '\n'; std::cerr << e.getStackTrace() << '\n'; - } catch (const std::runtime_error& e) { + } catch (const std::runtime_error &e) { std::cerr << e.what() << '\n'; } catch (...) { std::cerr << "Error!\n";