diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3bc1c0a5..0676f33d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -59,7 +59,7 @@ apigenerator: script: - mkdir -p apifiles - python3 src/yaml2doxy.py --input src/gdxapi.yaml --template_folder src/templates --output apifiles/gdx.h - - python3 src/yaml2cwrap.py --input src/gdxapi.yaml --template_folder src/templates --output apifiles/cwrap.hpp + - python3 src/yaml2cwrap.py --input src/gdxapi.yaml --template_folder src/templates --output apifiles/gdxcwrap.hpp - > python3 src/yaml2cwrap.py @@ -72,7 +72,7 @@ apigenerator: - cp src/apigenerator/include/gc*.h apifiles - cp src/gdx.h generated/gdx.h - | - for f in "gdxcc.h" "gdxcc.c" "gdxcclib.cpp" "gclgms.h" "gdx.h" "cwrap.hpp" "gdxcppwrap.h"; do + for f in "gdxcc.h" "gdxcc.c" "gdxcclib.cpp" "gclgms.h" "gdx.h" "gdxcwrap.hpp" "gdxcppwrap.h"; do echo "Diffing 'apifiles/$f' with 'generated/$f'" if ! diff apifiles/$f generated/$f; then echo "Warning: $f stored in repo and freshly generated differ!" @@ -110,10 +110,11 @@ build-leg: - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON CMakeLists.txt - cmake --build . 2>&1 | tee build_log.txt - python3 ci/report_for_log.py gcc build_log.txt warnings.xml + - mv libgdx-static.a libgdx-linux.a needs: [fetch-ci-scripts,apigenerator] artifacts: name: gdx-leg - paths: [gdxtest,gdxwraptest,libgdxcclib64.so] + paths: [gdxtest,gdxwraptest,libgdxcclib64.so,libgdx-linux.a] expire_in: 2 hours reports: junit: warnings.xml @@ -143,10 +144,11 @@ build-deg: - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CXX_COMPILER=clang++ CMakeLists.txt - cmake --build . 2>&1 | tee build_log.txt - python3 ci/report_for_log.py clang build_log.txt warnings.xml + - mv libgdx-static.a libgdx-macos.a needs: [fetch-ci-scripts,apigenerator] artifacts: name: gdx-deg - paths: [gdxtest,gdxwraptest,libgdxcclib64.dylib] + paths: [gdxtest,gdxwraptest,libgdxcclib64.dylib,libgdx-macos.a] expire_in: 2 hours reports: junit: warnings.xml @@ -155,14 +157,20 @@ build-dac: stage: build tags: [macos-arm64] script: + - mv libgdxcclib64.dylib libgdxcclib64_deg.dylib + - mv libgdx-macos.a libgdx-macos-deg.a - cp apifiles/* src/ - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DCMAKE_CXX_COMPILER=clang++ CMakeLists.txt - cmake --build . 2>&1 | tee build_log.txt - python3 ci/report_for_log.py clang build_log.txt warnings.xml - needs: [fetch-ci-scripts,apigenerator] + - mv libgdxcclib64.dylib libgdxcclib64_dac.dylib + - mv libgdx-static.a libgdx-macos-dac.a + - lipo -create libgdxcclib64_deg.dylib libgdxcclib64_dac.dylib -output libgdxcclib64.dylib + - lipo -create libgdx-macos-deg.a libgdx-macos-dac.a -output libgdx-macos.a + needs: [fetch-ci-scripts,apigenerator,build-deg] artifacts: name: gdx-dac - paths: [gdxtest,gdxwraptest,libgdxcclib64.dylib] + paths: [gdxtest,gdxwraptest,libgdxcclib64.dylib,libgdx-macos.a] expire_in: 2 hours reports: junit: warnings.xml @@ -345,7 +353,7 @@ deploy-gitlab-github: - if: $CI_COMMIT_BRANCH == 'main' when: on_success tags: [linux] - needs: [build-leg, build-dac, build-wei, apigenerator] + needs: [build-leg,build-dac,build-wei,apigenerator] image: name: registry.gams.com/devel/gdx/leg/builder-deploy:latest entrypoint: [""] # prevent startup.sh @@ -366,8 +374,9 @@ deploy-gitlab-github: -n "${GDX_RELEASE_NAME}" - sleep 10s # make sure the release is available to reference - cp Release/gdxcclib64.dll apifiles/*.h apifiles/*.c apifiles/*.cpp . + - cp Release/gdx-static.lib libgdx-windows.lib - | - for fn in libgdxcclib64.so gdxcclib64.dll libgdxcclib64.dylib gclgms.h gcmutex.h gdxcc.h gdxcc.c gdxcclib.cpp + for fn in libgdxcclib64.so gdxcclib64.dll libgdxcclib64.dylib libgdx-macos.a libgdx-linux.a libgdx-windows.lib gclgms.h gcmutex.h gdxcc.h gdxcc.c gdxcwrap.hpp gdxcclib.cpp do GITHUB_TOKEN=${GITHUB_TOKEN} github-release -v upload -R -u GAMS-dev -r gdx -t "${GDX_TAG_NAME}" -n $fn -f $fn done diff --git a/CMakeLists.txt b/CMakeLists.txt index fd42993d..f5405f41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,14 +29,12 @@ if (MSVC) endif (MSVC) if (UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wreturn-type -Wmissing-declarations -Wno-unknown-pragmas") -endif (UNIX) - -if (APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wreturn-type -Wmissing-declarations -Wno-unknown-pragmas") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DZ_HAVE_UNISTD_H") -elseif(UNIX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat-truncation=0") -endif (APPLE) + if(NOT APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat-truncation=0") + endif (NOT APPLE) +endif (UNIX) set(common src/gmsstrm.h src/gmsstrm.cpp @@ -65,12 +63,14 @@ set(tests src/tests/datastoragetests.cpp ) +set(inc-dirs zlib src generated) + # Dynamic library / shared object add_library(gdxcclib64 SHARED ${common} generated/gdxcclib.cpp ) if(UNIX) target_compile_options(gdxcclib64 PRIVATE -fvisibility=hidden) endif() -target_include_directories(gdxcclib64 PRIVATE zlib src generated) +target_include_directories(gdxcclib64 PRIVATE ${inc-dirs}) if (APPLE) set(cclib-link-options "-Bdynamic") elseif(UNIX) # Linux @@ -81,10 +81,15 @@ endif() target_link_libraries(gdxcclib64 ${mylibs} ${cclib-link-options}) set_property(TARGET gdxcclib64 PROPERTY POSITION_INDEPENDENT_CODE ON) +# Static library +add_library(gdx-static STATIC ${common}) +target_include_directories(gdx-static PRIVATE ${inc-dirs}) +set_property(TARGET gdx-static PROPERTY POSITION_INDEPENDENT_CODE ON) + # Unit test suite (against statically compiled GDX) -add_executable(gdxtest ${common} ${tests}) -target_include_directories(gdxtest PRIVATE zlib src generated) -target_link_libraries(gdxtest ${mylibs}) +add_executable(gdxtest ${tests}) +target_include_directories(gdxtest PRIVATE ${inc-dirs}) +target_link_libraries(gdxtest gdx-static ${mylibs}) # Compare against Delphi reference behavior when running against GDX performance library files if(UNIX) @@ -95,7 +100,7 @@ endif() if(EXISTS ${gams43-apifiles-path}gdxcc.c) add_executable(delphi-diff-tests ${common} src/tests/doctestmain.cpp src/tests/delphidifftests.cpp ${gams43-apifiles-path}gdxcc.c) -target_include_directories(delphi-diff-tests PRIVATE zlib src generated) +target_include_directories(delphi-diff-tests PRIVATE ${inc-dirs}) target_link_libraries(delphi-diff-tests ${mylibs}) if(UNIX) target_compile_options(delphi-diff-tests PRIVATE -DGC_NO_MUTEX) @@ -115,10 +120,35 @@ target_compile_options(gdxwraptest PRIVATE -DGXFILE_CPPWRAP -DGC_NO_MUTEX) # Standalone GDX example program 1 add_executable(xp_example1 ${common} src/examples/xp_example1.cpp) -target_include_directories(xp_example1 PRIVATE zlib src generated) +target_include_directories(xp_example1 PRIVATE ${inc-dirs}) target_link_libraries(xp_example1 ${mylibs}) # Standalone GDX example program 2 add_executable(xp_example2 ${common} src/examples/xp_example2.cpp generated/optcc.c) -target_include_directories(xp_example2 PRIVATE zlib src generated) +target_include_directories(xp_example2 PRIVATE ${inc-dirs}) target_link_libraries(xp_example2 ${mylibs}) + +# Standalone GDX example program 3 (associative "supply.demand" str -> double (level)) +add_executable(xp_associative ${common} src/examples/xp_associative.cpp) +target_include_directories(xp_associative PRIVATE ${inc-dirs}) +target_link_libraries(xp_associative ${mylibs}) + +# Standalone GDX example program 4 (associative {supply,demand} vector -> double (level)) +add_executable(xp_associative_vec ${common} src/examples/xp_associative_vec.cpp) +target_include_directories(xp_associative_vec PRIVATE ${inc-dirs}) +target_link_libraries(xp_associative_vec ${mylibs}) + +# Standalone GDX example program 5 (data write) +if(UNIX) + set(cur-apifiles-path /home/andre/gamsdist/apifiles/C/api/) +else() + set(cur-apifiles-path C:/GAMS/46/apifiles/C/api/) +endif() +if(EXISTS ${cur-apifiles-path}gmdcc.c) + add_executable(xp_dataWrite ${common} src/examples/xp_dataWrite.cpp ${cur-apifiles-path}gmdcc.c) + target_include_directories(xp_dataWrite PRIVATE ${inc-dirs} ${cur-apifiles-path}) + target_link_libraries(xp_dataWrite ${mylibs}) + if(UNIX) + target_compile_options(xp_dataWrite PRIVATE -DGC_NO_MUTEX) + endif() +endif() diff --git a/README.md b/README.md index 7a9ae5cf..760d70f5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # GAMS Data eXchange (GDX) + ## Table of Contents * [GAMS Data eXchange (GDX)](#gams-data-exchange-gdx) @@ -36,84 +37,123 @@ * [Example 6 (Python)](#example-6-python) * [Example 7 (C#)](#example-7-c) * [Example 8 (Java)](#example-8-java) - * [Conversion issues when moving from GAMS 22.5 to 22.6](#conversion-issues-when-moving-from-gams-225-to-226) - * [Files in the apifiles directory](#files-in-the-apifiles-directory) + ## Basic information on GDX file format -The GAMS modeling language is a domain specific language tailored towards mathematical optimization. The language reflects -the basic building blocks (symbols) of an algebraic optimization model: Sets, parameters, scalars, decision variables, and -equations. While declaring the symbols in the GAMS language is rather straightforward and concise, defining their values -(which must be done prior to running the optimization for exogenous symbols like sets, parameters and scalars) might be -comparatively cumbersome. In many applications, the actual data for the symbols is also already stored in some other -location like a file or database. In order to have an efficient way to load data into a model, store the solution -results and in general exchange information with other applications, the GDX file format was conceived. +The [GAMS modeling language](https://www.gams.com/latest/docs/UG_MAIN.html#UG_Language_Environment) is a domain specific +language tailored towards mathematical optimization. The language reflects the basic building blocks (symbols) of an +algebraic optimization model: + +- [Sets](https://www.gams.com/latest/docs/UG_SetDefinition.html), +- [parameters](https://www.gams.com/latest/docs/UG_Parameters.html), +- [scalars](https://www.gams.com/latest/docs/UG_DataEntry.html#UG_DataEntry_Scalars), +- [decision variables](https://www.gams.com/latest/docs/UG_Variables.html), +- and [equations](https://www.gams.com/latest/docs/UG_Equations.html). + +While declaring the symbols in the GAMS language is rather straightforward and concise, defining their values (which +must be done prior to running the optimization for exogenous symbols like sets, parameters and scalars) might be +comparatively cumbersome. In many applications, the actual data for the symbols is also already stored in some other +location like a file or database. In order to have an efficient way to load data into a model, store the solution +results and in general exchange information with other applications, the +[GDX file format](https://www.gams.com/latest/docs/UG_GDX.html) was conceived. ### Information contained inside a GDX file + - Unique elements (strings used to identify set elements) - Acronyms as shorthand names for specific numeric values - Symbols - - with their attributes... - - Type: Set, Alias, Parameter, Scalar, Variable, Equation - - Dimensionality - - User info - - Explanatory text - - ...and data (records) + - with their attributes... + - Type: Set, Alias, Parameter, Scalar, Variable, Equation + - Dimensionality + - User info + - Explanatory text + - ...and data (records) -Records are mapping from the domain of the symbol to the value space with up to 5 fields (level, marginal, lower bound, upper bound, scale) +Records are mapping from the domain of the symbol to the value space with up to 5 fields (level, marginal, lower bound, +upper bound, scale) The actual data might be stored verbatim or compressed (using zlib). +*Please note:* a GDX file does **not** store a model formulation or executable statements. + ### Features of the GDX API -For efficiency reasons (both read/write-speeds and disk usage) the GDX format is a binary format that cannot be easily -processed using a text editor. Hence, looking at the contents of a GDX file is ideally done via a graphical user interface -like the GDX viewer included in GAMS Studio or the `gdxdump` console utility included in the GAMS distribution. In order -to write conversion utilities between GDX and various other data file formats, an API is needed. This API has the following features: + +For efficiency reasons (both read/write-speeds and disk usage) the GDX format is a binary format that cannot be easily +processed using a text editor. Hence, looking at the contents of a GDX file is ideally done via a graphical user +interface +like the GDX viewer included in GAMS Studio or the `gdxdump` console utility included in the GAMS distribution. In order +to write conversion utilities between GDX and various other data file formats, an API is needed. This API has the +following features: + - Reading list of symbols and UELs - Reading data from a symbol (metadata, records) - Writing a new symbol (metadata, records) - Bindings to multiple languages -The GDX API is very powerful with fine-grained control and is also used at GAMS internally. There exist more comfortable object-oriented -alternatives for programming languages like `gams-cpp` and GAMS Python. +The GDX API is very powerful with fine-grained control and is also used at GAMS internally. ## Setting up and building GDX ### Accessing GDX from a custom application -The GDX API is available for multiple programming languages including: -- C/C++ -- .NET (Visual Basic, C#) -- Java -- Python -Depending on the language choice, the required steps to have it accessible from your development environment slightly differ. +The GDX API can be directly accessed from C/C++ via the library contained in this repository. Although there is a main +GDX object for representing a file in this interface, it is mostly procedural and offers many functions operating on +elementary data types instead of a sophisticated class hierarchy. + +For an easier to use object-oriented interface GAMS offers wrappers for multiple programming languages including: + +- [C++](https://www.gams.com/latest/docs/API_CPP_OVERVIEW.html) with source code available on + [GitHub](https://git.gams.com/devel/gams-cpp) +- [.NET](https://www.gams.com/latest/docs/apis/dotnet/DOTNET_OVERVIEW.html) (Visual Basic, C#) +- [Java](https://www.gams.com/latest/docs/API_JAVA_OVERVIEW.html) +- [Python](https://www.gams.com/latest/docs/API_PY_CONTROL.html) + +Even more abstraction is offered by the GAMS Transfer libraries for +[Python](https://www.gams.com/latest/docs/API_PY_GAMSTRANSFER.html) and +[R](https://www.gams.com/latest/docs/API_R_GAMSTRANSFER.html). ### Building GDX from source -The GDX library is written in C++ and built via CMake. This repository contains a GitLab CI YAML that describes a -pipeline which builds GDX and runs the unit test suite. + +The GDX library is written in C++17 and built via [CMake](https://cmake.org/). + +This repository contains a GitLab CI YAML that describes a pipeline which + +- builds GDX for all supported platforms (Windows, macOS, Linux) with Doxygen documentation, libraries, and examples, +- runs its unit test suite, +- checks for memory leaks with [valgrind memcheck](https://valgrind.org/docs/manual/mc-manual.html), +- and checks for performance regressions against GAMS 43 legacy Delphi GDX library. Please run + ``` git clone https://github.com/madler/zlib zlib ``` -inside the root-directory of the `gdx`-repository to make ZLIB available. -doctest and apigenerator are included in this repo (as file and submodule respectively). +inside the root-directory of the `gdx`-repository to make the zlib compression library available. + +[doctest](https://github.com/doctest/doctest) and [apigenerator](https://github.com/GAMS-dev/apigenerator) are included +in this repo (as file and submodule respectively). **Dependencies**: -- ZLIB (compression library) -- doctest -**Build tools**: -- GAMS API generator (language binding/wrapper tool) -- CMake (build system) -- C++17 compiler (e.g. GCC, clang, MSVC, Intel C++) +- [zlib](https://github.com/madler/zlib) (compression library) +- [doctest](https://github.com/doctest/doctest) + +**Build tools**: + +- [GAMS API generator](https://github.com/GAMS-dev/apigenerator) (language binding/wrapper tool) +- [CMake](https://cmake.org/) (build system) +- C++17 compiler (e.g. [GCC](https://gcc.gnu.org/), [clang](https://clang.llvm.org/), + [MSVC](https://visualstudio.microsoft.com/), + [Intel C++](https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compiler.html#gs.12zqsa)) ## Reference documentation -A full detailed Doxygen-generated API reference is available [here](https://gams-dev.github.io/gdx/classgdx_1_1TGXFileObj.html). +A full detailed Doxygen-generated API reference is +available [here](https://gams-dev.github.io/gdx/classgdx_1_1TGXFileObj.html). ## Introduction into using GDX API @@ -415,12 +455,15 @@ the gdxDataReadMap function. | Expand (-1) | Map the unique element value to the user defined value. Use gdxGetUEL to get the string representation. If a user mapping was not defined for this element, define a user mapping automatically using the next higher user map value. | | Filter number (>0) | Map the unique element value to the user defined value. Use gdxGetUEL to get the string representation. If the element is not enabled in the filter for this index position, the record is flagged as an error record and it will be skipped. The filter number is specified using the gdxFilterRegisterStart function. | -Referring to the following GAMS fragment, we want to read the parameter `A`. The set `I` is the domain for the first index; +Referring to the following GAMS fragment, we want to read the parameter `A`. The set `I` is the domain for the first +index; there is no domain for the second index position: + ``` Set I /.../; Parameter A(I,*); ``` + Assuming we have read set `I` already, the following code snapshot illustrates how to read parameter `A`. ```cpp @@ -476,18 +519,22 @@ if(NewLastMapped > LastMapped) { ### Dealing with acronyms In GAMS we can use acronyms in places where we can use a floating point number as in the following example: + ``` set i /i1*i5/; acronym acro1, acro2; parameter A(i) /i1=1, i2=acro1, i3=3, i4=acro2, i5=5/; display A; ``` + The result of the display statement looks like: + ``` ---- 4 PARAMETER A i1 1.000, i2 acro1, i3 3.000, i4 acro2, i5 5.000 ``` + As we write data to a GDX file, the system keeps track which acronyms were used in the data written. Before we close the GDX file, we share the identifiers used for each acronym used. When reading a GDX file, we share all acronym identifiers @@ -495,6 +542,7 @@ and their corresponding index before reading any data. Doing so will replace the acronym indices stored in the GDX file by the one we provide. The example below illustrates these steps. + ```cpp TGXFileObj gdx; TgdxUELIndex UELS; @@ -595,12 +643,17 @@ The following table organizes the functions by category: | Acronyms | gdxAcronymIndex gdxAcronymValue gdxAcronymCount gdxAcronymGetInfo gdxAcronymSetInfo | + ## Transition diagram -Some GDX operations only make sense after running other routines for preparation beforehand. For example, writing records -to a symbol in raw mode can only be done after the symbol has been "opened" for writing in raw mode. Hence, the GDX operations -follow a state machine like logic that prevents the user from executing operations that are not sensible in the current state -of the GDX object. The routines documented below follow certain input / output state transitions. Routines not documented +Some GDX operations only make sense after running other routines for preparation beforehand. For example, writing +records +to a symbol in raw mode can only be done after the symbol has been "opened" for writing in raw mode. Hence, the GDX +operations +follow a state machine like logic that prevents the user from executing operations that are not sensible in the current +state +of the GDX object. The routines documented below follow certain input / output state transitions. Routines not +documented below have no special state requirements. ### Diagram for general operations @@ -618,6 +671,7 @@ graph TD fr_init -->|gdxAcronymSetInfo| fr_init fw_init -->|gdxAcronymSetInfo| fw_init ``` + ### Diagram for read operations ```mermaid @@ -645,6 +699,7 @@ graph TD - `**` stay in `fr_{raw,map,str}_data` iff. there are more records to read, move to `fr_init` otherwise. ### Diagram for write operations + ```mermaid graph TD fw_init -->|gdxDataWriteRawStart| fw_raw_data @@ -659,6 +714,7 @@ graph TD ``` ### Diagram for UEL operations + ```mermaid graph TD fr_init -->|gdxUELRegisterRawStart| f_raw_elem @@ -671,12 +727,17 @@ graph TD f_map_elem -->|gdxUELRegisterDone| fr_init f_str_elem -->|gdxUELRegisterDone| fr_init ``` + ## Example programs ### Example 1 (GAMS) -In this modified version of the trnsport.gms model, we use an external program to generate data for the demand parameter. After we solve the model, we write the solution to a GDX file, and call the external program again to read the variable from the GDX file. + +In this modified version of the trnsport.gms model, we use an external program to generate data for the demand +parameter. After we solve the model, we write the solution to a GDX file, and call the external program again to read +the variable from the GDX file. + ``` $Title trnsport model using gdx files $EOLCOM // @@ -740,6 +801,7 @@ execute 'gdxexdp.exe %gams.sysdir% results.gdx'; // do something with the soluti ``` ### Example 2 (C) + ```c /* Use this command to compile the example: @@ -939,6 +1001,7 @@ int main (int argc, char *argv[]) { ``` ### Example 3 (C++) + ```cpp /* Use this command to compile the example: @@ -1055,6 +1118,7 @@ int main(int argc, char *argv[]) { ``` ### Example 4 (VB.NET) + ```vb Module xp_example1 '/////////////////////////////////////////////////////////////// @@ -1195,6 +1259,7 @@ End Module ``` ### Example 6 (Python) + ```python import argparse import sys @@ -1219,7 +1284,7 @@ if __name__ == "__main__": if not gdx.gdxOpenWrite(gdx_h, "demanddata.gdx", "xp_example1")[0]: raise Exception("Error gdxOpenWrite") if not gdx.gdxDataWriteStrStart( - gdx_h, "Demand", "Demand data", 1, gdx.GMS_DT_PAR, 0 + gdx_h, "Demand", "Demand data", 1, gdx.GMS_DT_PAR, 0 ): raise Exception("Error gdxDataWriteStrStart") @@ -1280,6 +1345,7 @@ if __name__ == "__main__": ``` ### Example 7 (C#) + ```csharp /////////////////////////////////////////////////////////////// // This program generates demand data for a modified version // @@ -1430,6 +1496,7 @@ namespace xp_example1 ``` ### Example 8 (Java) + ```java package com.gams.xp_examples; import com.gams.api.*; @@ -1561,34 +1628,3 @@ static void WriteData(String s, double V) { } ``` - -## Conversion issues when moving from GAMS 22.5 to 22.6 - -- maximum number of dimensions = 20 (was 10) -- maximum length of an identifier or unique element = 63 (was 31) -- support for acronyms -- support for domain information - -Backward compatibility: -- GAMS and all gdx utilities will write gdx files in the new format -- GAMS and all gdx utilities can read older gdx formats -- The gdxcopy utility can convert between different gdx formats - (assuming that dimension and namelength is supported) - -Libraries: -- `gdxio.dll` is still available but the new library is called `(lib)gdxcclib64.dll` (substitute `.dll` with the extension for your platform, e.g. `.so` or `.dylib`) -- `gdxio.dll` cannot read the new gdx format - -API: -- Functions in the library that used to return a boolean, now return an integer (zero for false, non-zero for true) -- Before we can read or write a gdx file, we need to create a valid gdx object. The function `gdxCreate` will create such an object -- The functions `gdxOpenRead` and `gdxOpenWrite` no longer create the gdx object pointer, they require an object pointer that has been initialized using gdxCreate or similar functions - -## Files in the apifiles directory - -The following sections describe the various files included in the apifiles -directory. All functions will use the gdxcclib library (like `gdxcclib64.dll` on -Windows). The entry points in the library can be loaded static (by the operating system) -or dynamic. Dynamic loading provides more control when an entry point is missing -or the interface has changed. Static loading will cause an exception to be generated -for example for a missing entry point without much feedback about the error. diff --git a/changelog.yaml b/changelog.yaml index 334f4325..6d6d0a87 100644 --- a/changelog.yaml +++ b/changelog.yaml @@ -1,4 +1,10 @@ --- +- 7.11.1: + - gdxUMUelGet was modified to accept a NULL pointer for the user UEL index mapping "UelMap". + - Added two new example programs xp_associative(_vec) and xp_dataWrite. + - macOS libraries deployed with GitHub release are now universal (also support Intel) instead of only arm64. + - Also release libraries for static linking on all platforms. + - Added gdxDataWriteRawStartKeyBounds that allows supplying UEL index lower and upper bounds per symbol dimension. - 7.10.1: - First open source release of GDX eXPert-level API. Compatible with GAMS 45. - Added gdxAllowBogusDomains to get flag to ignore using 1-dim sets as domain when their elements are not tracked (see gdxStoreDomainSets). diff --git a/generated/gdxcc.c b/generated/gdxcc.c index 4ba325fb..deb0bfa1 100644 --- a/generated/gdxcc.c +++ b/generated/gdxcc.c @@ -1,9 +1,9 @@ -/* C code generated by API Generator ac63ded for gdx version 10 +/* C code generated by API Generator 281dde9 for gdx version 11 * * GAMS - Loading mechanism for GAMS Expert-Level APIs * - * Copyright (c) 2016-2023 GAMS Software GmbH - * Copyright (c) 2016-2023 GAMS Development Corp. + * Copyright (c) 2016-2024 GAMS Software GmbH + * Copyright (c) 2016-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -710,6 +710,32 @@ int GDX_CALLCONV d_gdxDataWriteRawStart (gdxHandle_t pgdx, const char *SyId, co printAndReturn(gdxDataWriteRawStart,5,int ) } +/** Start writing a new symbol in raw mode with bounds for UEL key indices being known in advance. + * This helps potentially reducing the required storage for the keys as smaller integral datatypes can be used. + * Returns zero if the operation is not possible. + * @param pgdx gdx object handle + * @param SyId Name of the symbol (up to 63 characters). The first character of a symbol must be a letter. Following symbol characters may be letters, digits, and underscores. Symbol names must be new and unique. + * @param ExplTxt Explanatory text for the symbol (up to 255 characters). + * @param Dimen Dimension of the symbol (up to 20). + * @param Typ Type of the symbol (set=0, parameter=1, variable=2, equation=3, alias=4). + * @param UserInfo User field value storing additional data; GAMS follows the following conventions:
Type Value(s)
Aliased Set The symbol number of the aliased set, or zero for the universe
Set Zero
Parameter Zero
Variable The variable type: binary=1, integer=2, positive=3, negative=4, free=5, sos1=6, sos2=7, semicontinous=8, semiinteger=9
Equation The equation type: eque=53, equg=54, equl=55, equn=56, equx=57, equc=58, equb=59
+ * @param MinUELIndices Minimum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + * @param MaxUELIndices Maximum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + */ +int GDX_CALLCONV d_gdxDataWriteRawStartKeyBounds (gdxHandle_t pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int MinUELIndices[], const int MaxUELIndices[]) +{ + int d_s[]={3,11,11,3,3,3,51,51}; + GAMS_UNUSED(pgdx) + GAMS_UNUSED(SyId) + GAMS_UNUSED(ExplTxt) + GAMS_UNUSED(Dimen) + GAMS_UNUSED(Typ) + GAMS_UNUSED(UserInfo) + GAMS_UNUSED(MinUELIndices) + GAMS_UNUSED(MaxUELIndices) + printAndReturn(gdxDataWriteRawStartKeyBounds,7,int ) +} + /** Write a data element in string mode. Each element string must follow the GAMS rules for unique elements. Returns zero if the operation is not possible. * @param pgdx gdx object handle * @param KeyStr The index for this element using strings for the unique elements. One entry for each symbol dimension. @@ -1772,7 +1798,7 @@ XLibraryLoad (const char *dllName, char *errBuf, int errBufSize) LOADIT(XCheck, "C__XCheck"); LOADIT(XAPIVersion, "C__XAPIVersion"); - if (!XAPIVersion(10,errBuf,&cl)) + if (!XAPIVersion(11,errBuf,&cl)) return 1; LOADIT_ERR_OK(gdxSetLoadPath, "C__gdxSetLoadPath"); @@ -1819,6 +1845,7 @@ XLibraryLoad (const char *dllName, char *errBuf, int errBufSize) {int s[]={3,11,11,3,3,3}; CheckAndLoad(gdxDataWriteMapStart,5,"C__"); } {int s[]={3,51,53}; CheckAndLoad(gdxDataWriteRaw,2,"C__"); } {int s[]={3,11,11,3,3,3}; CheckAndLoad(gdxDataWriteRawStart,5,"C__"); } + {int s[]={3,11,11,3,3,3,51,51}; CheckAndLoad(gdxDataWriteRawStartKeyBounds,7,"C__"); } {int s[]={3,55,53}; CheckAndLoad(gdxDataWriteStr,2,"C__"); } {int s[]={3,11,11,3,3,3}; CheckAndLoad(gdxDataWriteStrStart,5,"C__"); } {int s[]={3,12}; CheckAndLoad(gdxGetDLLVersion,1,"C__"); } diff --git a/generated/gdxcc.h b/generated/gdxcc.h index 09d11e46..08e227ce 100644 --- a/generated/gdxcc.h +++ b/generated/gdxcc.h @@ -1,11 +1,11 @@ /* gdxcc.h * Header file for C-style interface to the GDX library - * generated by API Generator ac63ded for gdx version 10 + * generated by API Generator 281dde9 for gdx version 11 * * GAMS - Loading mechanism for GAMS Expert-Level APIs * - * Copyright (c) 2016-2023 GAMS Software GmbH - * Copyright (c) 2016-2023 GAMS Development Corp. + * Copyright (c) 2016-2024 GAMS Software GmbH + * Copyright (c) 2016-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,7 +30,7 @@ #if ! defined(_GDXCC_H_) # define _GDXCC_H_ -#define GDXAPIVERSION 10 +#define GDXAPIVERSION 11 #if defined(_WIN32) && defined(__GNUC__) # include #endif @@ -178,6 +178,7 @@ int GDX_CALLCONV d_gdxDataWriteMap (gdxHandle_t pgdx, const int KeyInt[], const int GDX_CALLCONV d_gdxDataWriteMapStart (gdxHandle_t pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo); int GDX_CALLCONV d_gdxDataWriteRaw (gdxHandle_t pgdx, const int KeyInt[], const double Values[]); int GDX_CALLCONV d_gdxDataWriteRawStart (gdxHandle_t pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo); +int GDX_CALLCONV d_gdxDataWriteRawStartKeyBounds (gdxHandle_t pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int MinUELIndices[], const int MaxUELIndices[]); int GDX_CALLCONV d_gdxDataWriteStr (gdxHandle_t pgdx, const char *KeyStr[], const double Values[]); int GDX_CALLCONV d_gdxDataWriteStrStart (gdxHandle_t pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo); int GDX_CALLCONV d_gdxGetDLLVersion (gdxHandle_t pgdx, char *V); @@ -602,6 +603,25 @@ typedef int (GDX_CALLCONV *gdxDataWriteRawStart_t) (gdxHandle_t pgdx, const cha */ GDX_FUNCPTR(gdxDataWriteRawStart); +typedef int (GDX_CALLCONV *gdxDataWriteRawStartKeyBounds_t) (gdxHandle_t pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int MinUELIndices[], const int MaxUELIndices[]); +/** Start writing a new symbol in raw mode with bounds for UEL key indices being known in advance. + * + * This helps potentially reducing the required storage for the keys as smaller integral datatypes can be used. + * + * Returns zero if the operation is not possible. + * + * @param pgdx gdx object handle + * @param SyId Name of the symbol (up to 63 characters). The first character of a symbol must be a letter. Following symbol characters may be letters, digits, and underscores. Symbol names must be new and unique. + * @param ExplTxt Explanatory text for the symbol (up to 255 characters). + * @param Dimen Dimension of the symbol (up to 20). + * @param Typ Type of the symbol (set=0, parameter=1, variable=2, equation=3, alias=4). + * @param UserInfo User field value storing additional data; GAMS follows the following conventions:
Type Value(s)
Aliased Set The symbol number of the aliased set, or zero for the universe
Set Zero
Parameter Zero
Variable The variable type: binary=1, integer=2, positive=3, negative=4, free=5, sos1=6, sos2=7, semicontinous=8, semiinteger=9
Equation The equation type: eque=53, equg=54, equl=55, equn=56, equx=57, equc=58, equb=59
+ * @param MinUELIndices Minimum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + * @param MaxUELIndices Maximum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + * @return Non-zero if the operation is possible, zero otherwise. + */ +GDX_FUNCPTR(gdxDataWriteRawStartKeyBounds); + typedef int (GDX_CALLCONV *gdxDataWriteStr_t) (gdxHandle_t pgdx, const char *KeyStr[], const double Values[]); /** Write a data element in string mode. Each element string must follow the GAMS rules for unique elements. Returns zero if the operation is not possible. * diff --git a/generated/gdxcclib.cpp b/generated/gdxcclib.cpp index 5ba07abb..9c765625 100644 --- a/generated/gdxcclib.cpp +++ b/generated/gdxcclib.cpp @@ -1,9 +1,9 @@ -/* C library code generated by API Generator ac63ded for gdx version 10 +/* C library code generated by API Generator 281dde9 for gdx version 11 * * GAMS - Loading mechanism for GAMS Expert-Level APIs * - * Copyright (c) 2016-2023 GAMS Software GmbH - * Copyright (c) 2016-2023 GAMS Development Corp. + * Copyright (c) 2016-2024 GAMS Software GmbH + * Copyright (c) 2016-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,7 @@ #include #include -#include "cwrap.hpp" +#include "gdxcwrap.hpp" #include "gclgms.h" #if defined(_WIN32) @@ -98,6 +98,7 @@ #define C__gdxDataWriteMapStart c__gdxdatawritemapstart #define C__gdxDataWriteRaw c__gdxdatawriteraw #define C__gdxDataWriteRawStart c__gdxdatawriterawstart +#define C__gdxDataWriteRawStartKeyBounds c__gdxdatawriterawstartkeybounds #define C__gdxDataWriteStr c__gdxdatawritestr #define C__gdxDataWriteStrStart c__gdxdatawritestrstart #define C__gdxGetDLLVersion c__gdxgetdllversion @@ -165,6 +166,7 @@ #define D__gdxDataSliceUELS d__gdxdatasliceuels #define D__gdxDataWriteMapStart d__gdxdatawritemapstart #define D__gdxDataWriteRawStart d__gdxdatawriterawstart +#define D__gdxDataWriteRawStartKeyBounds d__gdxdatawriterawstartkeybounds #define D__gdxDataWriteStr d__gdxdatawritestr #define D__gdxDataWriteStrStart d__gdxdatawritestrstart #define D__gdxGetDLLVersion d__gdxgetdllversion @@ -345,8 +347,8 @@ GDX_API int GDX_CALLCONV C__XAPIVersion(int api, char *Msg, int *comp); GDX_API int GDX_CALLCONV C__XAPIVersion(int api, char *Msg, int *comp) { *comp = 0; - if (api >= 10) { - if (api == 10) { + if (api >= 11) { + if (api == 11) { *comp = 1; strcpy(Msg,"gdxcclib: Client version and DLL version are the same."); } @@ -356,15 +358,17 @@ GDX_API int GDX_CALLCONV C__XAPIVersion(int api, char *Msg, int *comp) } return 1; } - if ((api == 10) || (api == 9) || (api == 8) || (api == 7)) { + if ((api == 11) || (api == 10) || (api == 9) || (api == 8) || (api == 7)) { *comp = 2; strcpy(Msg,"gdxcclib: Client version is compatible to this version of the DLL."); return 1; } - sprintf(Msg,"gdxcclib: The API is too old for the used library, API version: %d, library version: 10",api); + snprintf(Msg,GMS_SSSIZE-1,"gdxcclib: The API is too old for the used library, API version: %d, library version: 11",api); return 0; } /* C__XAPIVersion */ +#define mymin(a, b) ((a) < (b) ? (a) : (b)) + GDX_API int GDX_CALLCONV D__XAPIVersion(int api, char *Msg, int *comp); GDX_API int GDX_CALLCONV D__XAPIVersion(int api, char *Msg, int *comp) { @@ -375,8 +379,9 @@ GDX_API int GDX_CALLCONV D__XAPIVersion(int api, char *Msg, int *comp) Msg_sst[0] = '\0'; XAPIVersion_result = C__XAPIVersion(api,Msg_sst,comp); Msg_local = Msg+1; - strncpy(Msg_local,Msg_sst,(strlen(Msg_sst)>255?255:strlen(Msg_sst))); - Msg[0] = strlen(Msg_sst); + size_t slen = mymin(strlen(Msg_sst), 255); + memcpy(Msg_local,Msg_sst,slen); + Msg[0] = slen; return XAPIVersion_result; } /* D__XAPIVersion */ @@ -393,7 +398,7 @@ static int CheckSign(const char *funcn, int DLLNrArg, int ClNrArg, int DLLsign[] Msg[0] = '\0'; if(DLLNrArg != ClNrArg) { - sprintf(Msg,"gdxcclib: %s has wrong number of arguments.",funcn); + snprintf(Msg,GMS_SSSIZE-1,"gdxcclib: %s has wrong number of arguments.",funcn); return 0; } else @@ -402,7 +407,7 @@ static int CheckSign(const char *funcn, int DLLNrArg, int ClNrArg, int DLLsign[] { if(DLLsign[i] != Clsign[i]) { - sprintf(Msg,"gdxcclib: %s has wrong argument types.",funcn); + snprintf(Msg,GMS_SSSIZE-1,"gdxcclib: %s has wrong argument types.",funcn); return 0; } } @@ -413,7 +418,7 @@ static int CheckSign(const char *funcn, int DLLNrArg, int ClNrArg, int DLLsign[] GDX_API int GDX_CALLCONV C__XCheck(const char *funcn, int ClNrArg, int Clsign[], char *Msg); GDX_API int GDX_CALLCONV C__XCheck(const char *funcn, int ClNrArg, int Clsign[], char *Msg) { - int DLLsign[7]; + int DLLsign[8]; if(!strcmp(funcn,"gdxAcronymAdd")) { DLLsign[0] = 3;DLLsign[1] = 11;DLLsign[2] = 11;DLLsign[3] = 3; @@ -589,6 +594,11 @@ GDX_API int GDX_CALLCONV C__XCheck(const char *funcn, int ClNrArg, int Clsign[], DLLsign[0] = 3;DLLsign[1] = 11;DLLsign[2] = 11;DLLsign[3] = 3;DLLsign[4] = 3;DLLsign[5] = 3; return CheckSign(funcn,5,ClNrArg,DLLsign,Clsign,Msg); } + else if(!strcmp(funcn,"gdxDataWriteRawStartKeyBounds")) + { + DLLsign[0] = 3;DLLsign[1] = 11;DLLsign[2] = 11;DLLsign[3] = 3;DLLsign[4] = 3;DLLsign[5] = 3;DLLsign[6] = 51;DLLsign[7] = 51; + return CheckSign(funcn,7,ClNrArg,DLLsign,Clsign,Msg); + } else if(!strcmp(funcn,"gdxDataWriteStr")) { DLLsign[0] = 3;DLLsign[1] = 55;DLLsign[2] = 53; @@ -896,7 +906,7 @@ GDX_API int GDX_CALLCONV C__XCheck(const char *funcn, int ClNrArg, int Clsign[], } else { - sprintf(Msg,"gdxcclib: %s cannot be found in library.",funcn); + snprintf(Msg,GMS_SSSIZE-1,"gdxcclib: %s cannot be found in library.",funcn); return 0; } } /* C__XCheck */ @@ -913,8 +923,9 @@ GDX_API int GDX_CALLCONV D__XCheck(const unsigned char *funcn, int ClNrArg, int funcn_sst[funcn[0]] = '\0'; XCheck_result = C__XCheck(funcn_sst,ClNrArg,Clsign,Msg_sst); Msg_local = Msg+1; - strncpy(Msg_local,Msg_sst,(strlen(Msg_sst)>255?255:strlen(Msg_sst))); - Msg[0] = strlen(Msg_sst); + size_t slen = mymin(strlen(Msg_sst), 255); + memcpy(Msg_local,Msg_sst, slen); + Msg[0] = slen; return XCheck_result; } /* D__XCheck */ @@ -925,10 +936,12 @@ GDX_API int GDX_CALLCONV D__gdxXCheck(const unsigned char *funcn, int ClNrArg, i } /* D__gdxXCheck */ +GDX_API void GDX_CALLCONV C__gdxSetLoadPath(const char *s); GDX_API void GDX_CALLCONV C__gdxSetLoadPath(const char *s) { gdxSetLoadPath(s); } /* C__gdxSetLoadPath */ +GDX_API void GDX_CALLCONV C__gdxGetLoadPath(char *s); GDX_API void GDX_CALLCONV C__gdxGetLoadPath(char *s) { gdxGetLoadPath(s); } /* C__gdxGetLoadPath */ @@ -1145,6 +1158,12 @@ GDX_API int GDX_CALLCONV C__gdxDataWriteRawStart(TGXFileRec_t *TGXFile, const ch return gdxDataWriteRawStart(TGXFile, SyId, ExplTxt, Dimen, Typ, UserInfo); } +GDX_API int GDX_CALLCONV C__gdxDataWriteRawStartKeyBounds(TGXFileRec_t *TGXFile, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int MinUELIndices[], const int MaxUELIndices[]); +GDX_API int GDX_CALLCONV C__gdxDataWriteRawStartKeyBounds(TGXFileRec_t *TGXFile, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int MinUELIndices[], const int MaxUELIndices[]) +{ + return gdxDataWriteRawStartKeyBounds(TGXFile, SyId, ExplTxt, Dimen, Typ, UserInfo, MinUELIndices, MaxUELIndices); +} + GDX_API int GDX_CALLCONV C__gdxDataWriteStr(TGXFileRec_t *TGXFile, const char *KeyStr[], const double Values[]); GDX_API int GDX_CALLCONV C__gdxDataWriteStr(TGXFileRec_t *TGXFile, const char *KeyStr[], const double Values[]) { @@ -1499,10 +1518,10 @@ GDX_API int GDX_CALLCONV D__gdxAcronymGetInfo(TGXFileRec_t *TGXFile, int N, char char *Txt_local; gdxAcronymGetInfo_result = gdxAcronymGetInfo(TGXFile, N, AName_sst, Txt_sst, AIndx); AName_local = AName+1; - strncpy(AName_local,AName_sst,(strlen(AName_sst)>255?255:strlen(AName_sst))); + memcpy(AName_local,AName_sst,mymin(strlen(AName_sst),255)); AName[0] = strlen(AName_sst); Txt_local = Txt+1; - strncpy(Txt_local,Txt_sst,(strlen(Txt_sst)>255?255:strlen(Txt_sst))); + memcpy(Txt_local,Txt_sst,mymin(strlen(Txt_sst),255)); Txt[0] = strlen(Txt_sst); return gdxAcronymGetInfo_result; } @@ -1515,7 +1534,7 @@ GDX_API int GDX_CALLCONV D__gdxAcronymName(TGXFileRec_t *TGXFile, double V, char char *AName_local; gdxAcronymName_result = gdxAcronymName(TGXFile, V, AName_sst); AName_local = AName+1; - strncpy(AName_local,AName_sst,(strlen(AName_sst)>255?255:strlen(AName_sst))); + memcpy(AName_local,AName_sst,mymin(strlen(AName_sst),255)); AName[0] = strlen(AName_sst); return gdxAcronymName_result; } @@ -1616,7 +1635,7 @@ GDX_API int GDX_CALLCONV D__gdxDataReadStr(TGXFileRec_t *TGXFile, char *KeyStr, for(KeyStr_cnt=0;KeyStr_cnt255?255:strlen(KeyStr_pdim[KeyStr_cnt]))); + memcpy(KeyStr + KeyStr_cnt*256 + 1,KeyStr_pdim[KeyStr_cnt],mymin(strlen(KeyStr_pdim[KeyStr_cnt]),255)); KeyStr[KeyStr_cnt*256] = strlen(KeyStr_pdim[KeyStr_cnt]); } return gdxDataReadStr_result; @@ -1641,7 +1660,7 @@ GDX_API int GDX_CALLCONV D__gdxDataSliceUELS(TGXFileRec_t *TGXFile, const int Sl for(KeyStr_cnt=0;KeyStr_cnt255?255:strlen(KeyStr_pdim[KeyStr_cnt]))); + memcpy(KeyStr + KeyStr_cnt*256 + 1,KeyStr_pdim[KeyStr_cnt],mymin(strlen(KeyStr_pdim[KeyStr_cnt]),255)); KeyStr[KeyStr_cnt*256] = strlen(KeyStr_pdim[KeyStr_cnt]); } return gdxDataSliceUELS_result; @@ -1675,6 +1694,20 @@ GDX_API int GDX_CALLCONV D__gdxDataWriteRawStart(TGXFileRec_t *TGXFile, const ch return gdxDataWriteRawStart_result; } +GDX_API int GDX_CALLCONV D__gdxDataWriteRawStartKeyBounds(TGXFileRec_t *TGXFile, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int MinUELIndices[], const int MaxUELIndices[]); +GDX_API int GDX_CALLCONV D__gdxDataWriteRawStartKeyBounds(TGXFileRec_t *TGXFile, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int MinUELIndices[], const int MaxUELIndices[]) +{ + int gdxDataWriteRawStartKeyBounds_result; + char SyId_sst[256]; + char ExplTxt_sst[256]; + strncpy(SyId_sst,(char *) SyId + 1,(unsigned char) SyId[0]); + SyId_sst[(unsigned char) SyId[0]] = '\0'; + strncpy(ExplTxt_sst,(char *) ExplTxt + 1,(unsigned char) ExplTxt[0]); + ExplTxt_sst[(unsigned char) ExplTxt[0]] = '\0'; + gdxDataWriteRawStartKeyBounds_result = gdxDataWriteRawStartKeyBounds(TGXFile, SyId_sst, ExplTxt_sst, Dimen, Typ, UserInfo, MinUELIndices, MaxUELIndices); + return gdxDataWriteRawStartKeyBounds_result; +} + GDX_API int GDX_CALLCONV D__gdxDataWriteStr(TGXFileRec_t *TGXFile, const char *KeyStr, const double Values[]); GDX_API int GDX_CALLCONV D__gdxDataWriteStr(TGXFileRec_t *TGXFile, const char *KeyStr, const double Values[]) { @@ -1716,7 +1749,7 @@ GDX_API int GDX_CALLCONV D__gdxGetDLLVersion(TGXFileRec_t *TGXFile, char *V) char *V_local; gdxGetDLLVersion_result = gdxGetDLLVersion(TGXFile, V_sst); V_local = V+1; - strncpy(V_local,V_sst,(strlen(V_sst)>255?255:strlen(V_sst))); + memcpy(V_local,V_sst,mymin(strlen(V_sst),255)); V[0] = strlen(V_sst); return gdxGetDLLVersion_result; } @@ -1729,7 +1762,7 @@ GDX_API int GDX_CALLCONV D__gdxErrorStr(TGXFileRec_t *TGXFile, int ErrNr, char * char *ErrMsg_local; gdxErrorStr_result = gdxErrorStr(TGXFile, ErrNr, ErrMsg_sst); ErrMsg_local = ErrMsg+1; - strncpy(ErrMsg_local,ErrMsg_sst,(strlen(ErrMsg_sst)>255?255:strlen(ErrMsg_sst))); + memcpy(ErrMsg_local,ErrMsg_sst,mymin(strlen(ErrMsg_sst),255)); ErrMsg[0] = strlen(ErrMsg_sst); return gdxErrorStr_result; } @@ -1744,10 +1777,10 @@ GDX_API int GDX_CALLCONV D__gdxFileVersion(TGXFileRec_t *TGXFile, char *FileStr, char *ProduceStr_local; gdxFileVersion_result = gdxFileVersion(TGXFile, FileStr_sst, ProduceStr_sst); FileStr_local = FileStr+1; - strncpy(FileStr_local,FileStr_sst,(strlen(FileStr_sst)>255?255:strlen(FileStr_sst))); + memcpy(FileStr_local,FileStr_sst,mymin(strlen(FileStr_sst),255)); FileStr[0] = strlen(FileStr_sst); ProduceStr_local = ProduceStr+1; - strncpy(ProduceStr_local,ProduceStr_sst,(strlen(ProduceStr_sst)>255?255:strlen(ProduceStr_sst))); + memcpy(ProduceStr_local,ProduceStr_sst,mymin(strlen(ProduceStr_sst),255)); ProduceStr[0] = strlen(ProduceStr_sst); return gdxFileVersion_result; } @@ -1771,7 +1804,7 @@ GDX_API int GDX_CALLCONV D__gdxGetElemText(TGXFileRec_t *TGXFile, int TxtNr, cha char *Txt_local; gdxGetElemText_result = gdxGetElemText(TGXFile, TxtNr, Txt_sst, Node); Txt_local = Txt+1; - strncpy(Txt_local,Txt_sst,(strlen(Txt_sst)>255?255:strlen(Txt_sst))); + memcpy(Txt_local,Txt_sst,mymin(strlen(Txt_sst),255)); Txt[0] = strlen(Txt_sst); return gdxGetElemText_result; } @@ -1784,7 +1817,7 @@ GDX_API int GDX_CALLCONV D__gdxGetUEL(TGXFileRec_t *TGXFile, int UelNr, char *Ue char *Uel_local; gdxGetUEL_result = gdxGetUEL(TGXFile, UelNr, Uel_sst); Uel_local = Uel+1; - strncpy(Uel_local,Uel_sst,(strlen(Uel_sst)>255?255:strlen(Uel_sst))); + memcpy(Uel_local,Uel_sst,mymin(strlen(Uel_sst),255)); Uel[0] = strlen(Uel_sst); return gdxGetUEL_result; } @@ -1883,7 +1916,7 @@ GDX_API int GDX_CALLCONV D__gdxSymbolGetComment(TGXFileRec_t *TGXFile, int SyNr, char *Txt_local; gdxSymbolGetComment_result = gdxSymbolGetComment(TGXFile, SyNr, N, Txt_sst); Txt_local = Txt+1; - strncpy(Txt_local,Txt_sst,(strlen(Txt_sst)>255?255:strlen(Txt_sst))); + memcpy(Txt_local,Txt_sst,mymin(strlen(Txt_sst),255)); Txt[0] = strlen(Txt_sst); return gdxSymbolGetComment_result; } @@ -1907,7 +1940,7 @@ GDX_API int GDX_CALLCONV D__gdxSymbolGetDomainX(TGXFileRec_t *TGXFile, int SyNr, for(DomainIDs_cnt=0;DomainIDs_cnt255?255:strlen(DomainIDs_pdim[DomainIDs_cnt]))); + memcpy(DomainIDs + DomainIDs_cnt*256 + 1,DomainIDs_pdim[DomainIDs_cnt],mymin(strlen(DomainIDs_pdim[DomainIDs_cnt]),255)); DomainIDs[DomainIDs_cnt*256] = strlen(DomainIDs_pdim[DomainIDs_cnt]); } return gdxSymbolGetDomainX_result; @@ -1921,7 +1954,7 @@ GDX_API int GDX_CALLCONV D__gdxSymbolInfo(TGXFileRec_t *TGXFile, int SyNr, char char *SyId_local; gdxSymbolInfo_result = gdxSymbolInfo(TGXFile, SyNr, SyId_sst, Dimen, Typ); SyId_local = SyId+1; - strncpy(SyId_local,SyId_sst,(strlen(SyId_sst)>255?255:strlen(SyId_sst))); + memcpy(SyId_local,SyId_sst,mymin(strlen(SyId_sst),255)); SyId[0] = strlen(SyId_sst); return gdxSymbolInfo_result; } @@ -1934,7 +1967,7 @@ GDX_API int GDX_CALLCONV D__gdxSymbolInfoX(TGXFileRec_t *TGXFile, int SyNr, int char *ExplTxt_local; gdxSymbolInfoX_result = gdxSymbolInfoX(TGXFile, SyNr, RecCnt, UserInfo, ExplTxt_sst); ExplTxt_local = ExplTxt+1; - strncpy(ExplTxt_local,ExplTxt_sst,(strlen(ExplTxt_sst)>255?255:strlen(ExplTxt_sst))); + memcpy(ExplTxt_local,ExplTxt_sst,mymin(strlen(ExplTxt_sst),255)); ExplTxt[0] = strlen(ExplTxt_sst); return gdxSymbolInfoX_result; } @@ -2029,7 +2062,7 @@ GDX_API int GDX_CALLCONV D__gdxUMUelGet(TGXFileRec_t *TGXFile, int UelNr, char * char *Uel_local; gdxUMUelGet_result = gdxUMUelGet(TGXFile, UelNr, Uel_sst, UelMap); Uel_local = Uel+1; - strncpy(Uel_local,Uel_sst,(strlen(Uel_sst)>255?255:strlen(Uel_sst))); + memcpy(Uel_local,Uel_sst,mymin(strlen(Uel_sst),255)); Uel[0] = strlen(Uel_sst); return gdxUMUelGet_result; } diff --git a/generated/gdxcppwrap.h b/generated/gdxcppwrap.h index 82aa8fa0..d61b4575 100644 --- a/generated/gdxcppwrap.h +++ b/generated/gdxcppwrap.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * -* Copyright (c) 2017-2023 GAMS Software GmbH -* Copyright (c) 2017-2023 GAMS Development Corp. +* Copyright (c) 2017-2024 GAMS Software GmbH +* Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -305,6 +305,11 @@ class TGXFileObj return ::gdxDataWriteRawStart( pgx, SyId, ExplTxt, Dimen, Typ, UserInfo ); } + int gdxDataWriteRawStartKeyBounds( const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int *MinUELIndices, const int *MaxUELIndices ) + { + return ::gdxDataWriteRawStartKeyBounds( pgx, SyId, ExplTxt, Dimen, Typ, UserInfo, MinUELIndices, MaxUELIndices ); + } + int gdxDataWriteStr( const char **KeyStr, const double *Values ) { return ::gdxDataWriteStr( pgx, KeyStr, Values ); @@ -591,4 +596,4 @@ class TGXFileObj } }; -}// namespace gdx \ No newline at end of file +}// namespace gdx diff --git a/generated/cwrap.hpp b/generated/gdxcwrap.hpp similarity index 97% rename from generated/cwrap.hpp rename to generated/gdxcwrap.hpp index 4b8f40e3..b5f12e4f 100644 --- a/generated/cwrap.hpp +++ b/generated/gdxcwrap.hpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -44,6 +44,7 @@ extern "C" { #endif typedef struct TGXFileRec TGXFileRec_t; +typedef TGXFileRec_t* gdxHandle_t; typedef void( GDX_CALLCONV *TDataStoreProc_t )( const int Indx[], const double Vals[] ); typedef int( GDX_CALLCONV *TDataStoreExProc_t )( const int Indx[], const double Vals[], int DimFrst, void *Uptr ); @@ -105,6 +106,7 @@ int gdxDataWriteMap( TGXFileRec_t *pgdx, const int *KeyInt, const double *Values int gdxDataWriteMapStart( TGXFileRec_t *pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo ); int gdxDataWriteRaw( TGXFileRec_t *pgdx, const int *KeyInt, const double *Values ); int gdxDataWriteRawStart( TGXFileRec_t *pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo ); +int gdxDataWriteRawStartKeyBounds( TGXFileRec_t *pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int *MinUELIndices, const int *MaxUELIndices ); int gdxDataWriteStr( TGXFileRec_t *pgdx, const char **KeyStr, const double *Values ); int gdxDataWriteStrStart( TGXFileRec_t *pgdx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo ); int gdxGetDLLVersion( TGXFileRec_t *pgdx, char *V ); @@ -384,6 +386,11 @@ GDX_INLINE int gdxDataWriteRawStart( TGXFileRec_t *pgx, const char *SyId, const return reinterpret_cast( pgx )->gdxDataWriteRawStart(SyId, ExplTxt, Dimen, Typ, UserInfo ); } +GDX_INLINE int gdxDataWriteRawStartKeyBounds( TGXFileRec_t *pgx, const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int *MinUELIndices, const int *MaxUELIndices ) +{ + return reinterpret_cast( pgx )->gdxDataWriteRawStartKeyBounds(SyId, ExplTxt, Dimen, Typ, UserInfo, MinUELIndices, MaxUELIndices ); +} + GDX_INLINE int gdxDataWriteStr( TGXFileRec_t *pgx, const char **KeyStr, const double *Values ) { return reinterpret_cast( pgx )->gdxDataWriteStr(KeyStr, Values ); @@ -636,6 +643,11 @@ GDX_INLINE int gdxUMFindUEL( TGXFileRec_t *pgx, const char *Uel, int *UelNr, int GDX_INLINE int gdxUMUelGet( TGXFileRec_t *pgx, int UelNr, char *Uel, int *UelMap ) { + if(!UelMap) + { + int tmpUelMap; + return reinterpret_cast( pgx )->gdxUMUelGet(UelNr, Uel, tmpUelMap ); + } return reinterpret_cast( pgx )->gdxUMUelGet(UelNr, Uel, *UelMap ); } @@ -715,4 +727,4 @@ GDX_INLINE void setCallByRef( TGXFileRec_t *TGXFile, const char *FuncName, int c #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/src/apigenerator b/src/apigenerator index ac63ded2..281dde9f 160000 --- a/src/apigenerator +++ b/src/apigenerator @@ -1 +1 @@ -Subproject commit ac63ded2d72746d16627586bc04f533130be51f6 +Subproject commit 281dde9fcd867b15f59acbf44258e50bffab1575 diff --git a/src/datastorage.h b/src/datastorage.h index a0d5781f..9ddf78a3 100644 --- a/src/datastorage.h +++ b/src/datastorage.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/examples/xp_associative.cpp b/src/examples/xp_associative.cpp new file mode 100644 index 00000000..cee98300 --- /dev/null +++ b/src/examples/xp_associative.cpp @@ -0,0 +1,144 @@ +/** + * + * GAMS - General Algebraic Modeling System C++ API + * + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + Use this command to compile the example: + cl xp_associative.cpp ../C/api/gdxcc.c -I../C/api +*/ + +#include +#include +#include +#include + +#include "gdx.h" + +using namespace std::literals::string_literals; + +std::map fillXLevelMapFromGDX(const std::string &filename); +void processXLevelMap(std::map &xlevel); + +int main( int argc, const char **argv ) +{ + try + { + const auto filename {argc >= 2 ? std::string{argv[1]} : "trnsport.gdx"s}; + auto xlevel {fillXLevelMapFromGDX( filename )}; + processXLevelMap( xlevel ); + } + catch(std::runtime_error &e) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; +} + +std::map fillXLevelMapFromGDX(const std::string &filename) +{ + std::string msg; + gdx::TGXFileObj gdx { msg }; + if(!msg.empty()) + throw std::runtime_error("Unable to instantiate GDX object: "s + msg); + + int errNr {}; + int rc {gdx.gdxOpenRead( filename.c_str(), errNr )}; + if( !rc || errNr != 0 ) + { + std::array msgBuf{}; + gdx::TGXFileObj::gdxErrorStr( errNr, msgBuf.data() ); + throw std::runtime_error("*** Error opening trnsport.gdx: "s + msgBuf.data()); + } + + int varNr{}; + rc = gdx.gdxFindSymbol( "x", varNr ); + if( !rc ) + throw std::runtime_error("*** Cannot find symbol 'x'"); + + std::array varName {}; + int dim {}, varType {}; + rc = gdx.gdxSymbolInfo( varNr, varName.data(), dim, varType ); + if(!rc) + throw std::runtime_error("Getting symbol info for variable (x) #"s + std::to_string(varNr) + " failed!"s); + if( dim != 2 || GMS_DT_VAR != varType ) + throw std::runtime_error("*** x is not a two dimensional variable. dim:"s + std::to_string(dim) + " type:"s + std::to_string(varType)); + + int nrRecs{}; + if( !gdx.gdxDataReadStrStart( varNr, nrRecs ) ) + throw std::runtime_error("*** Cannot read symbol 'x'"s); + + static gdxStrIndexPtrs_t idx; + static gdxStrIndex_t idxXXX; + GDXSTRINDEXPTRS_INIT( idxXXX, idx ); + + std::map xlevel; + + for( int i = 0; i < nrRecs; i++ ) + { + gdxValues_t values; + int n{}; + gdx.gdxDataReadStr( idx, values, n ); + std::string key = ""s + idx[0] + "."s + idx[1]; + xlevel[key] = values[GMS_VAL_LEVEL]; + } + + rc = gdx.gdxDataReadDone(); + if( !rc ) + throw std::runtime_error("*** Unable to finish reading records of symbol 'x'"s); + + gdx.gdxClose(); + + return xlevel; +} + +void processXLevelMap(std::map &xlevel) +{ + std::cout << "-----\nrandom access of a key that does not exist:" << std::endl; + auto key {"seattle.something else"s}; + if( xlevel.find( key ) != xlevel.end() ) + std::cout << key << " : " << xlevel[key] << std::endl; + else + std::cout << "key does not exist" << std::endl; + + std::cout << "-----\nrandom access of a key that does exist:" << std::endl; + key = "seattle.chicago"s; + if( xlevel.find( key ) != xlevel.end() ) + std::cout << key << " : " << xlevel[key] << std::endl; + else + std::cout << "key does not exist" << std::endl; + + std::cout << "-----\niterate through keys and perform random access to get the values:" << std::endl; + + for(const auto &[k,v] : xlevel) + std::cout << k << " : " << v << std::endl; + + std::cout << "-----\nchange the value of a key and access it once again:" << std::endl; + key = "seattle.chicago"; + xlevel[key] = 111.1; + std::cout << key << " : " << xlevel[key] << std::endl; + + std::cout << "\nxp_associative DONE" << std::endl; +} \ No newline at end of file diff --git a/src/examples/xp_associative_vec.cpp b/src/examples/xp_associative_vec.cpp new file mode 100644 index 00000000..d76d7d52 --- /dev/null +++ b/src/examples/xp_associative_vec.cpp @@ -0,0 +1,145 @@ +/** + * + * GAMS - General Algebraic Modeling System C++ API + * + * Copyright (c) 2017-2023 GAMS Software GmbH + * Copyright (c) 2017-2023 GAMS Development Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + Use this command to compile the example: + cl xp_associative_vec.cpp ../C/api/gdxcc.c -I../C/api +*/ + +#include +#include +#include +#include + +#include "gdx.h" + +using namespace std::literals::string_literals; + +std::map, double> loadXLevelMapFromGDX( const std::string &filename ); + +void processMap( std::map, double> &xlevel ); + +int main( int argc, char *argv[] ) +{ + try + { + std::string filename { argc >= 2 ? std::string { argv[1] } : "trnsport.gdx"s }; + auto xlevel { loadXLevelMapFromGDX( filename ) }; + processMap( xlevel ); + } + catch( std::runtime_error &e ) + { + std::cout << e.what() << std::endl; + return 1; + } + return 0; +} + +std::map, double> loadXLevelMapFromGDX( const std::string &filename ) +{ + std::string msg; + gdx::TGXFileObj gdx { msg }; + if( !msg.empty() ) + throw std::runtime_error( "*** Could not load GDX library!" ); + + int errNr {}; + int rc = gdx.gdxOpenRead( filename.c_str(), errNr ); + if( !rc || errNr != 0 ) + { + std::array msgBuf {}; + gdx::TGXFileObj::gdxErrorStr( errNr, msgBuf.data() ); + throw std::runtime_error( "*** Error opening trnsport.gdx: "s + msgBuf.data() ); + } + + int varNr {}; + rc = gdx.gdxFindSymbol( "x", varNr ); + if( !rc ) + throw std::runtime_error( "*** Cannot find symbol 'x'"s ); + + int dim {}, varType {}; + std::array varName {}; + rc = gdx.gdxSymbolInfo( varNr, varName.data(), dim, varType ); + if( !rc ) + throw std::runtime_error( "Unable to query symbol info for symbol 'x'"s ); + if( dim != 2 || GMS_DT_VAR != varType ) + throw std::runtime_error( "**** x is not a two dimensional variable. dim:"s + std::to_string( dim ) + " type:"s + std::to_string( varType ) ); + + int nrRecs {}; + rc = gdx.gdxDataReadStrStart( varNr, nrRecs ); + if( !rc ) + throw std::runtime_error( "*** Cannot read symbol 'x'"s ); + + static gdxStrIndexPtrs_t idx; + static gdxStrIndex_t idxXXX; + GDXSTRINDEXPTRS_INIT( idxXXX, idx ); + + std::map, double> xlevel; + + for( int i = 0; i < nrRecs; i++ ) + { + std::vector key( 2 ); + gdxValues_t values; + int n {}; + gdx.gdxDataReadStr( idx, values, n ); + key[0] = idx[0]; + key[1] = idx[1]; + xlevel[key] = values[GMS_VAL_LEVEL]; + } + + gdx.gdxClose(); + + return xlevel; +} + +void processMap( std::map, double> &xlevel ) +{ + std::cout << "-----\nrandom access of a key that does not exist:\n"; + std::vector key { "seattle"s, "something else"s }; + if( xlevel.find( key ) != xlevel.end() ) + std::cout << key[0] << "." << key[1] << " : " << xlevel[key] << std::endl; + else + std::cout << "key does not exist\n"; + + std::cout << "-----\nrandom access of a key that does exist:" << std::endl; + key[0] = "seattle"; + key[1] = "chicago"; + if( xlevel.find( key ) != xlevel.end() ) + std::cout << key[0] << "." << key[1] << " : " << xlevel[key] << std::endl; + else + std::cout << "key does not exist\n"; + + std::cout << "-----\niterate through keys and perform random access to get the values:\n"; + for( const auto &[keys, v]: xlevel ) + std::cout << keys.front() << "." << keys[1] << " : " << v << std::endl; + + std::cout << "-----\nchange the value of a key and access it once again:\n"; + key[0] = "seattle"; + key[1] = "chicago"; + xlevel[key] = 111.1; + std::cout << key[0] << "." << key[1] << " : " << xlevel[key] << std::endl; + + std::cout << "\nxp_associative_vec DONE" << std::endl; +} diff --git a/src/examples/xp_dataWrite.cpp b/src/examples/xp_dataWrite.cpp new file mode 100644 index 00000000..f4a75668 --- /dev/null +++ b/src/examples/xp_dataWrite.cpp @@ -0,0 +1,417 @@ +/** + * + * GAMS - General Algebraic Modeling System C++ API + * + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/* + Use this command to compile the example (Windows): + cl xp_dataWrite.cpp ../C/api/gdxcc.c ../C/api/gmdcc.c -I../C/api + Use this command to compile the example (Unix): + g++ xp_dataWrite.cpp ../C/api/gdxcc.c ../C/api/gmdcc.c -I../C/api -ldl +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "gdx.h" +#include "gmdcc.h" + +using namespace std::literals::string_literals; + +enum writeMode +{ + ordered, + oneOOO, + reversed +}; + +class worker +{ + std::unique_ptr gdx {}; + gmdHandle_t gmdHandle {}; + static constexpr int size = 200; + char iarrayC[size][GMS_SSSIZE] {};// GMS_UEL_IDENT_SIZE? + char jarrayC[size][GMS_SSSIZE] {}; + char karrayC[size][GMS_SSSIZE] {}; + clock_t tstart {}; + int IndxI[GMS_MAX_INDEX_DIM] {}; + gdxStrIndex_t IndxC {}; + gdxStrIndexPtrs_t IndxCPtrs {}; + gdxValues_t Values {}; + + static void ReportIOError( int N, const std::string &msg ); + + void ReportGDXError() const; + + void ReportGMDError() const; + + void PrintDiff( const std::string &msg, clock_t tm ) const; + +public: + void initC( const std::string &sysDir ); + + void useStr( const std::string &fileName, const std::string &txt, writeMode mode ); + + void useRaw( const std::string &fileName, const std::string &txt ); + + void useMap( const std::string &fileName, const std::string &txt, writeMode mode ); + + void useGmd( const std::string &fileName, const std::string &txt ); +}; + +void worker::ReportIOError( int N, const std::string &msg ) +{ + std::cout << "**** Fatal I/O Error = " << N << " when calling " << msg << std::endl; + exit( 1 ); +} + +void worker::ReportGDXError() const +{ + char s[GMS_SSSIZE]; + std::cout << "**** Fatal GDX Error" << std::endl; + gdx::TGXFileObj::gdxErrorStr( gdx->gdxGetLastError(), s ); + std::cout << "**** " << s << std::endl; + exit( 1 ); +} + +void worker::ReportGMDError() const +{ + char s[GMS_SSSIZE]; + std::cout << "**** Fatal GMD Error" << std::endl; + gmdGetLastError( gmdHandle, s ); + std::cout << "**** " << s << std::endl; + exit( 1 ); +} + +void worker::PrintDiff( const std::string &msg, clock_t tm ) const +{ + const float diff = ( (float) tm - (float) tstart ) / CLOCKS_PER_SEC; + std::cout << msg << diff << std::endl; +} + +void worker::initC( const std::string &sysDir ) +{ + std::string msgStr; + gdx = std::make_unique( msgStr ); + if( !msgStr.empty() ) + throw std::runtime_error( "**** Could not load GDX (c) library\n**** \n"s ); + + char msg[GMS_SSSIZE]; + gdx->gdxGetDLLVersion( msg ); + std::cout << "Using GDX DLL version: " << msg << std::endl; + + if( !gmdCreateD( &gmdHandle, sysDir.c_str(), msg, sizeof( msg ) ) ) + { + std::cout << "**** Could not load GMD (c) library" << std::endl + << "**** " << msg << std::endl; + exit( 1 ); + } + + for( int i = 0; i < size; i++ ) + { + snprintf( iarrayC[i], GMS_UEL_IDENT_SIZE, "i%d", i ); + snprintf( jarrayC[i], GMS_UEL_IDENT_SIZE, "j%d", i ); + snprintf( karrayC[i], GMS_UEL_IDENT_SIZE, "k%d", i ); + } + + GDXSTRINDEXPTRS_INIT( IndxC, IndxCPtrs ); + Values[GMS_VAL_LEVEL] = 11; +} + +void worker::useStr( const std::string &fileName, const std::string &txt, writeMode mode ) +{ + int ErrNr, dummy; + tstart = clock(); + gdx->gdxOpenWrite( fileName.c_str(), "example", ErrNr ); + if( ErrNr ) ReportIOError( ErrNr, "gdxOpenWrite" ); + + if( !gdx->gdxUELRegisterStrStart() ) ReportGDXError(); + for( const auto &i: iarrayC ) + if( !gdx->gdxUELRegisterStr( i, dummy ) ) ReportGDXError(); + for( const auto &j: jarrayC ) + if( !gdx->gdxUELRegisterStr( j, dummy ) ) ReportGDXError(); + for( const auto &k: karrayC ) + if( !gdx->gdxUELRegisterStr( k, dummy ) ) ReportGDXError(); + if( !gdx->gdxUELRegisterDone() ) ReportGDXError(); + + if( !gdx->gdxDataWriteStrStart( "Demand", "Demand data", 3, GMS_DT_PAR, 0 ) ) ReportGDXError(); + + switch( mode ) + { + case ordered: + for( auto &i: iarrayC ) + { + strcpy( IndxC[0], + i );//this would be quicker, but "unfair" to compare it with the c++ approach: IndxCPtrs[0] = iarrayC[i]; + for( auto &j: jarrayC ) + { + strcpy( IndxC[1], j ); + for( auto &k: karrayC ) + { + strcpy( IndxC[2], k ); + if( !gdx->gdxDataWriteStr( (const char **) IndxCPtrs, Values ) ) ReportGDXError(); + } + } + } + break; + case oneOOO: + for( int i = 0; i < size; i++ ) + { + strcpy( IndxC[0], iarrayC[i] ); + for( int j = 0; j < size; j++ ) + { + strcpy( IndxC[1], jarrayC[j] ); + for( int k = 0; k < size; k++ ) + { + strcpy( IndxC[2], karrayC[k] ); + if( i + j + k > 0 ) + if( !gdx->gdxDataWriteStr( (const char **) IndxCPtrs, Values ) ) ReportGDXError(); + } + } + } + strcpy( IndxC[0], iarrayC[0] ); + strcpy( IndxC[1], jarrayC[0] ); + strcpy( IndxC[2], karrayC[0] ); + if( !gdx->gdxDataWriteStr( (const char **) IndxCPtrs, Values ) ) ReportGDXError(); + break; + case reversed: + for( int i = size - 1; i > -1; i-- ) + { + strcpy( IndxC[0], iarrayC[i] ); + for( int j = size - 1; j > -1; j-- ) + { + strcpy( IndxC[1], jarrayC[j] ); + for( int k = size - 1; k > -1; k-- ) + { + strcpy( IndxC[2], karrayC[k] ); + if( !gdx->gdxDataWriteStr( (const char **) IndxCPtrs, Values ) ) ReportGDXError(); + } + } + } + break; + } + + PrintDiff( "Before Done (" + txt + "): ", clock() ); + + if( !gdx->gdxDataWriteDone() ) ReportGDXError(); + ErrNr = gdx->gdxClose(); + if( ErrNr ) ReportIOError( ErrNr, "gdxClose" ); + + PrintDiff( "Running time (" + txt + "): ", clock() ); +} + +void worker::useRaw( const std::string &fileName, const std::string &txt ) +{ + int ErrNr; + + tstart = clock(); + + gdx->gdxOpenWrite( fileName.c_str(), "example", ErrNr ); + if( ErrNr ) ReportIOError( ErrNr, "gdxOpenWrite" ); + + if( !gdx->gdxUELRegisterRawStart() ) ReportGDXError(); + for( auto &i: iarrayC ) + if( !gdx->gdxUELRegisterRaw( i ) ) ReportGDXError(); + for( auto &j: jarrayC ) + if( !gdx->gdxUELRegisterRaw( j ) ) ReportGDXError(); + for( auto &k: karrayC ) + if( !gdx->gdxUELRegisterRaw( k ) ) ReportGDXError(); + if( !gdx->gdxUELRegisterDone() ) ReportGDXError(); + + if( !gdx->gdxDataWriteRawStart( "Demand", "Demand data", 3, GMS_DT_PAR, 0 ) ) ReportGDXError(); + + for( int i = 0; i < size; i++ ) + { + IndxI[0] = i + 1; + for( int j = 0; j < size; j++ ) + { + IndxI[1] = size + j + 1; + for( int k = 0; k < size; k++ ) + { + IndxI[2] = 2 * size + k + 1; + if( !gdx->gdxDataWriteRaw( IndxI, Values ) ) ReportGDXError(); + } + } + } + + PrintDiff( "Before Done (" + txt + "): ", clock() ); + + if( !gdx->gdxDataWriteDone() ) ReportGDXError(); + ErrNr = gdx->gdxClose(); + if( ErrNr ) ReportIOError( ErrNr, "gdxClose" ); + + PrintDiff( "Running time (" + txt + "): ", clock() ); +} + +void worker::useMap( const std::string &fileName, const std::string &txt, writeMode mode ) +{ + int ErrNr; + + tstart = clock(); + + gdx->gdxOpenWrite( fileName.c_str(), "example", ErrNr ); + if( ErrNr ) ReportIOError( ErrNr, "gdxOpenWrite" ); + + if( !gdx->gdxUELRegisterMapStart() ) ReportGDXError(); + for( int i = 0; i < size; i++ ) + if( !gdx->gdxUELRegisterMap( i, iarrayC[i] ) ) ReportGDXError(); + for( int j = 0; j < size; j++ ) + if( !gdx->gdxUELRegisterMap( size + j, jarrayC[j] ) ) ReportGDXError(); + for( int k = 0; k < size; k++ ) + if( !gdx->gdxUELRegisterMap( 2 * size + k, karrayC[k] ) ) ReportGDXError(); + if( !gdx->gdxUELRegisterDone() ) ReportGDXError(); + + if( !gdx->gdxDataWriteMapStart( "Demand", "Demand data", 3, GMS_DT_PAR, 0 ) ) ReportGDXError(); + + switch( mode ) + { + case ordered: + for( int i = 0; i < size; i++ ) + { + IndxI[0] = i; + for( int j = 0; j < size; j++ ) + { + IndxI[1] = size + j; + for( int k = 0; k < size; k++ ) + { + IndxI[2] = 2 * size + k; + if( !gdx->gdxDataWriteMap( IndxI, Values ) ) ReportGDXError(); + } + } + } + break; + case oneOOO: + for( int i = 0; i < size; i++ ) + { + IndxI[0] = i; + for( int j = 0; j < size; j++ ) + { + IndxI[1] = size + j; + for( int k = 0; k < size; k++ ) + { + IndxI[2] = 2 * size + k; + if( i + j + k > 0 ) + if( !gdx->gdxDataWriteMap( IndxI, Values ) ) ReportGDXError(); + } + } + } + + IndxI[0] = 0; + IndxI[1] = 0; + IndxI[2] = 0; + if( !gdx->gdxDataWriteMap( IndxI, Values ) ) ReportGDXError(); + break; + case reversed: + for( int i = size - 1; i > -1; i-- ) + { + IndxI[0] = i; + for( int j = size - 1; j > -1; j-- ) + { + IndxI[1] = size + j; + for( int k = size - 1; k > -1; k-- ) + { + IndxI[2] = 2 * size + k; + if( !gdx->gdxDataWriteMap( IndxI, Values ) ) ReportGDXError(); + } + } + } + break; + } + + PrintDiff( "Before Done (" + txt + "): ", clock() ); + + if( !gdx->gdxDataWriteDone() ) ReportGDXError(); + ErrNr = gdx->gdxClose(); + if( ErrNr ) ReportIOError( ErrNr, "gdxClose" ); + + PrintDiff( "Running time (" + txt + "): ", clock() ); +} + +void worker::useGmd( const std::string &fileName, const std::string &txt ) +{ + void *symPtr, *symRecPtr; + + tstart = clock(); + + if( !gmdAddSymbol( gmdHandle, "Demand", 3, GMS_DT_PAR, 0, "", &symPtr ) ) ReportGMDError(); + + for( auto &i: iarrayC ) + { + strcpy( IndxC[0], i ); + for( auto &j: jarrayC ) + { + strcpy( IndxC[1], j ); + for( auto &k: karrayC ) + { + strcpy( IndxC[2], k ); + if( !gmdAddRecord( gmdHandle, symPtr, (const char **) IndxCPtrs, &symRecPtr ) ) ReportGMDError(); + if( !gmdSetLevel( gmdHandle, symRecPtr, 11.0 ) ) ReportGMDError(); + } + } + } + + PrintDiff( "Before Done (" + txt + "): ", clock() ); + + if( !gmdWriteGDX( gmdHandle, fileName.c_str(), true ) ) ReportGMDError(); + + PrintDiff( "Running time (" + txt + "): ", clock() ); +} + +int main( int argc, char *argv[] ) +{ + if( argc != 2 ) + { + std::cout << "**** DataWrite: incorrect number of parameters" << std::endl; + exit( 1 ); + } + + std::string Sysdir { argv[1] }; + std::cout << "DataWrite using GAMS system directory: " << Sysdir << std::endl; + + worker w; + + std::cout << "Start using C API (aka use *char all the time)" << std::endl; + w.initC( Sysdir ); + + w.useStr( "stringOrderedC.gdx", "strOrdered", ordered ); + w.useStr( "string1oooC.gdx", "str1ooo", oneOOO ); + w.useStr( "stringRevOrdC.gdx", "strRevOrd", reversed ); + + w.useRaw( "raw.gdx", "raw" ); + + w.useMap( "mapOrdered.gdx", "mapOrdered", ordered ); + w.useMap( "map1ooo.gdx", "map1ooo", oneOOO ); + w.useMap( "mapRevOrd.gdx", "mapRevOrd", reversed ); + + w.useGmd( "gmd.gdx", "gmd" ); + + std::cout << "All data written" << std::endl; + return 0; +} diff --git a/src/examples/xp_example1.cpp b/src/examples/xp_example1.cpp index 92fb4bce..57859b12 100644 --- a/src/examples/xp_example1.cpp +++ b/src/examples/xp_example1.cpp @@ -2,8 +2,8 @@ * * GAMS - General Algebraic Modeling System C++ API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/examples/xp_example2.cpp b/src/examples/xp_example2.cpp index 48bafa94..3f02d66e 100644 --- a/src/examples/xp_example2.cpp +++ b/src/examples/xp_example2.cpp @@ -2,8 +2,8 @@ * * GAMS - General Algebraic Modeling System C++ API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/gdx.h b/src/gdx.h index 661582a4..38050159 100644 --- a/src/gdx.h +++ b/src/gdx.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -1594,6 +1594,79 @@ class TGXFileObj */ int gdxDataWriteRawStart( const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo ); + /** + * @brief Start writing a new symbol in raw mode with bounds for UEL key indices being known in advance. + * This + * helps potentially reducing the required storage for the keys as smaller integral datatypes can be + * used. + * Returns zero if the operation is not possible. + * @details Raw mode flushes new records immediately to the GDX file (unlike mapped or string mode). The key + * indices for the record are provided as unique element numbers. + * @param SyId Name of the symbol (up to 63 characters). The first character of a symbol must be a letter. + * Following symbol characters may be letters, digits, and underscores. Symbol names must be new and + * unique. + * @param ExplTxt Explanatory text for the symbol (up to 255 characters). + * @param Dimen Dimension of the symbol (up to 20). + * @param Typ Type of the symbol (set=0, parameter=1, variable=2, equation=3, alias=4). + * @param UserInfo User field value storing additional data; GAMS follows the following conventions: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
+ * Type + * + * Value(s) + *
+ * Aliased Set + * + * The symbol number of the aliased set, or zero for the universe + *
+ * Set + * + * Zero + *
+ * Parameter + * + * Zero + *
+ * Variable + * + * The variable type: binary=1, integer=2, positive=3, negative=4, free=5, sos1=6, sos2=7, + * semicontinous=8, semiinteger=9 + *
+ * Equation + * + * The equation type: eque=53, equg=54, equl=55, equn=56, equx=57, equc=58, equb=59 + *
+ * @param MinUELIndices Minimum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + * @param MaxUELIndices Maximum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + * @return Non-zero if the operation is possible, zero otherwise. + * @see gdxDataWriteRaw, gdxDataWriteDone + */ + int gdxDataWriteRawStartKeyBounds( const char *SyId, const char *ExplTxt, int Dimen, int Typ, int UserInfo, const int *MinUELIndices, const int *MaxUELIndices ); + /** * @brief Write a data element in string mode. Each element string must follow the GAMS rules for unique * elements. Returns zero if the operation is not possible. @@ -1780,4 +1853,4 @@ bool gdxGetDomainElements_DP_CallByRef {}, gdxDataReadRawFastEx_DP_CallByRef {}; }; -}// namespace gdx \ No newline at end of file +}// namespace gdx diff --git a/src/gdxapi.yaml b/src/gdxapi.yaml index 97f714f0..c0ffa606 100644 --- a/src/gdxapi.yaml +++ b/src/gdxapi.yaml @@ -1,8 +1,8 @@ --- title : GAMS Data Exchange API prefix : gdx -apiversion : 10 -compatibleversion : [10,9,8,7] +apiversion : 11 +compatibleversion : [11,10,9,8,7] DObject : TGXFile DUnit : gxfile @@ -10,7 +10,7 @@ USE_XXXLOADPATH : true MaxDimStyle : gdx UseCD : True -extracUse : '#include "cwrap.hpp"' +extracUse : '#include "gdxcwrap.hpp"' clibuse : True NOFORTRANCB : False @@ -597,6 +597,45 @@ functions: return: Non-zero if the operation is possible, zero otherwise. details: '

Raw mode flushes new records immediately to the GDX file (unlike mapped or string mode). The key indices for the record are provided as unique element numbers.

See: gdxDataWriteRaw, gdxDataWriteDone.

' group: Write Data + - gdxDataWriteRawStartKeyBounds: + type: int + parameters: + - SyId: + type: css + description: Name of the symbol (up to 63 characters). The first character of a symbol must be a letter. Following symbol characters may be letters, digits, and underscores. Symbol names must be new and unique. + - ExplTxt: + type: css + description: Explanatory text for the symbol (up to 255 characters). + - Dimen: + type: int + description: Dimension of the symbol (up to 20). + - Typ: + type: int + description: Type of the symbol (set=0, parameter=1, variable=2, equation=3, alias=4). + - UserInfo: + type: int + description: + "User field value storing additional data; GAMS follows the following conventions: + + + + + + +
Type Value(s)
Aliased Set The symbol number of the aliased set, or zero for the universe
Set Zero
Parameter Zero
Variable The variable type: binary=1, integer=2, positive=3, negative=4, free=5, sos1=6, sos2=7, semicontinous=8, semiinteger=9
Equation The equation type: eque=53, equg=54, equl=55, equn=56, equx=57, equc=58, equb=59
" + - MinUELIndices: + type: cII + description: Minimum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + - MaxUELIndices: + type: cII + description: Maximum UEL indices for each symbol dimension. Can help with shrinking storage for keys. + description: |- + Start writing a new symbol in raw mode with bounds for UEL key indices being known in advance. + This helps potentially reducing the required storage for the keys as smaller integral datatypes can be used. + Returns zero if the operation is not possible. + return: Non-zero if the operation is possible, zero otherwise. + details: '

Raw mode flushes new records immediately to the GDX file (unlike mapped or string mode). The key indices for the record are provided as unique element numbers.

See: gdxDataWriteRaw, gdxDataWriteDone.

' + group: Write Data - gdxDataWriteStr: type: int parameters: diff --git a/src/gmsdata.h b/src/gmsdata.h index 33062a8b..99c42592 100644 --- a/src/gmsdata.h +++ b/src/gmsdata.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/gmsobj.h b/src/gmsobj.h index 65b698f5..985d5c1e 100644 --- a/src/gmsobj.h +++ b/src/gmsobj.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/gmsstrm.h b/src/gmsstrm.h index 9fd4d892..65b8a14b 100644 --- a/src/gmsstrm.h +++ b/src/gmsstrm.h @@ -287,7 +287,7 @@ class TMiBufferedStreamDelphi : public TBufferedFileStreamDelphi if( v2 != patConstant ) order_type = PAT_BAD_ORDER; } } - }; + } void DetermineByteOrder(); diff --git a/src/gxfile.cpp b/src/gxfile.cpp index 81e1854e..16e6f443 100644 --- a/src/gxfile.cpp +++ b/src/gxfile.cpp @@ -37,6 +37,7 @@ #include // for operator<<, basic_ostream, cout, ostream #include // for map, operator==, _Rb_tree_const_iterator #include // for pair +#include #if defined( _WIN32 ) #include @@ -50,7 +51,14 @@ using namespace std::literals::string_literals; namespace gdx { +#if defined(NDEBUG) +static std::stringstream debugStream; +#else +#define debugStream std::cout +#endif + std::string QueryEnvironmentVariable( const std::string &Name ); + std::string QueryEnvironmentVariable( const std::string &Name ) { #if defined( _WIN32 ) @@ -394,7 +402,7 @@ int TGXFileObj::gdxOpenWrite( const char *FileName, const char *Producer, int &E int TGXFileObj::gdxOpenWriteEx( const char *FileName, const char *Producer, int Compr, int &ErrNr ) { if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) - std::cout << "gdxOpenWrite("s << FileName << ")\n"s;// NOTE: Not covered by unit tests yet. + debugStream << "gdxOpenWrite("s << FileName << ")\n"s;// NOTE: Not covered by unit tests yet. if( fmode != f_not_open ) { @@ -473,9 +481,9 @@ int TGXFileObj::gdxDataWriteStr( const char **KeyStr, const double *Values ) { // NOTE: Not covered by unit tests yet. if( !CheckMode( "DataWriteStr"s, fw_str_data ) ) return false; - std::cout << " Index =\n"; + debugStream << " Index =\n"; for( int D {}; D < FCurrentDim; D++ ) - std::cout << " " << KeyStr[D] << ( D + 1 < FCurrentDim ? "," : "" ) << "\n"; + debugStream << " " << KeyStr[D] << ( D + 1 < FCurrentDim ? "," : "" ) << "\n"; } // Could actually be GLOBAL_UEL_IDENT_SIZE but is ShortString in Delphi static std::array SVstorage; @@ -530,7 +538,7 @@ int TGXFileObj::gdxDataWriteDone() int TGXFileObj::gdxClose() { if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) - std::cout << "gdxClose("s << ( FFile ? FFile->GetFileName() : ""s ) << ")\n"s;// NOTE: Not covered by unit tests yet. + debugStream << "gdxClose("s << ( FFile ? FFile->GetFileName() : ""s ) << ")\n"s;// NOTE: Not covered by unit tests yet. std::string fnConv; if( utils::in( fmode, fw_raw_data, fw_map_data, fw_str_data ) )// unfinished write @@ -702,7 +710,7 @@ int TGXFileObj::gdxResetSpecialValues() if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "reset special vals, dump of readIntlValueMapDbl\n"s; + debugStream << "reset special vals, dump of readIntlValueMapDbl\n"s; const std::array, 5> svNameIndexPairs { { { "undef"s, sv_valund }, { "na"s, sv_valna }, @@ -710,7 +718,7 @@ int TGXFileObj::gdxResetSpecialValues() { "min"s, sv_valmin }, { "eps"s, sv_valeps } } }; for( auto &[svName, svIndex]: svNameIndexPairs ) - std::cout << svName << "="s << readIntlValueMapDbl[svIndex] << '\n'; + debugStream << svName << "="s << readIntlValueMapDbl[svIndex] << '\n'; } copyIntlMapDblToI64( intlValueMapDbl, intlValueMapI64 ); @@ -806,7 +814,7 @@ bool TGXFileObj::MajorCheckMode( const std::string_view Routine, const TgxModeSe void TGXFileObj::WriteTrace( const std::string_view s ) const { - std::cout << "gdxTrace " << TraceStr << ": " << s << '\n'; + debugStream << "gdxTrace " << TraceStr << ": " << s << '\n'; } bool TGXFileObj::IsGoodNewSymbol( const char *s ) @@ -828,10 +836,10 @@ void TGXFileObj::ReportError( int N ) { // NOTE: Not covered by unit tests yet. if( !MajContext.empty() ) - std::cout << "Error after call to " << MajContext << '\n'; + debugStream << "Error after call to " << MajContext << '\n'; std::array s {}; gdxErrorStr( N, s.data() ); - std::cout << "Error = " << N << " : " << s.data() << "\n"; + debugStream << "Error = " << N << " : " << s.data() << "\n"; } SetError( N ); LastRepError = N; @@ -858,11 +866,11 @@ bool TGXFileObj::CheckMode( const std::string_view Routine, const TgxModeSet &MS return true; } SetError( ERR_BADMODE ); - std::cout << "**** Error: " << Routine << " called out of context\n"; + debugStream << "**** Error: " << Routine << " called out of context\n"; if( !MajContext.empty() && !utils::sameText( MajContext, Routine ) ) - std::cout << " Previous major function called was " << MajContext << '\n'; - std::cout << " Current context = " << fmode_str[fmode] << '\n'; - std::cout << " Allowed = {"; + debugStream << " Previous major function called was " << MajContext << '\n'; + debugStream << " Current context = " << fmode_str[fmode] << '\n'; + debugStream << " Allowed = {"; bool f { true }; for( int M {}; M < tgxfilemode_count; M++ ) { @@ -870,11 +878,11 @@ bool TGXFileObj::CheckMode( const std::string_view Routine, const TgxModeSet &MS { if( f ) f = false; else - std::cout << ',';// NOTE: Not covered by unit tests yet. - std::cout << fmode_str[M]; + debugStream << ',';// NOTE: Not covered by unit tests yet. + debugStream << fmode_str[M]; } } - std::cout << "}\n"; + debugStream << "}\n"; return false; } @@ -1139,7 +1147,7 @@ int TGXFileObj::PrepareSymbolRead( const std::string_view Caller, int SyNr, cons catch( std::exception &e ) { // NOTE: Not covered by unit tests yet. - std::cout << "Exception: " << e.what() << "\n"; + debugStream << "Exception: " << e.what() << "\n"; AllocOk = false; } } @@ -1238,10 +1246,10 @@ bool TGXFileObj::DoWrite( const int *AElements, const double *AVals ) if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "DoWrite index: "s; + debugStream << "DoWrite index: "s; for( int D {}; D < FCurrentDim; D++ ) - std::cout << std::to_string( AElements[D] ) << ( D + 1 < FCurrentDim ? ","s : ""s ); - std::cout << '\n'; + debugStream << std::to_string( AElements[D] ) << ( D + 1 < FCurrentDim ? ","s : ""s ); + debugStream << '\n'; } int FDim { FCurrentDim + 1 }, delta {}; @@ -1361,7 +1369,7 @@ bool TGXFileObj::DoWrite( const int *AElements, const double *AVals ) } } if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) - std::cout << "level="s << AVals[GMS_VAL_LEVEL] << '\n';// NOTE: Not covered by unit tests yet. + debugStream << "level="s << AVals[GMS_VAL_LEVEL] << '\n';// NOTE: Not covered by unit tests yet. } DataCount++; if( utils::in( CurSyPtr->SDataType, dt_set, dt_alias ) ) @@ -1443,7 +1451,7 @@ bool TGXFileObj::DoRead( double *AVals, int &AFDim ) if (SV < 0 || SV >= vm_count) { AVals[DV] = 0.0; if(verboseTrace && TraceLevel >= TraceLevels::trl_errors) - std::cout << "WARNING: Special value (" << BSV << ") byte out of range {0,...,10}!" << std::endl; + debugStream << "WARNING: Special value (" << BSV << ") byte out of range {0,...,10}!" << std::endl; continue; } AVals[DV] = SV != vm_normal ? readIntlValueMapDbl[SV] : maybeRemap( FFile->ReadDouble() ); @@ -1457,7 +1465,7 @@ bool TGXFileObj::DoRead( double *AVals, int &AFDim ) AVals[GMS_VAL_LEVEL] = MapSetText[D]; } if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) - std::cout << "level="s << AVals[GMS_VAL_LEVEL] << '\n';// NOTE: Not covered by unit tests yet. + debugStream << "level="s << AVals[GMS_VAL_LEVEL] << '\n';// NOTE: Not covered by unit tests yet. } return true; } @@ -1865,7 +1873,7 @@ int TGXFileObj::gdxOpenReadXX( const char *Afn, int filemode, int ReadMode, int if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "gdxOpenRead("s << Afn << ")\n"s; + debugStream << "gdxOpenRead("s << Afn << ")\n"s; } auto FileErrorNr = [&]() { @@ -2176,10 +2184,10 @@ int TGXFileObj::gdxDataReadRaw( int *KeyInt, double *Values, int &DimFrst ) if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "DataReadRaw index: "s; + debugStream << "DataReadRaw index: "s; for( int D {}; D < FCurrentDim; D++ ) - std::cout << std::to_string( KeyInt[D] ) << ( D + 1 < FCurrentDim ? ","s : ""s ); - std::cout << '\n'; + debugStream << std::to_string( KeyInt[D] ) << ( D + 1 < FCurrentDim ? ","s : ""s ); + debugStream << '\n'; } return true; } @@ -2213,6 +2221,18 @@ int TGXFileObj::gdxDataWriteRawStart( const char *SyId, const char *ExplTxt, int return true; } +int TGXFileObj::gdxDataWriteRawStartKeyBounds( const char *SyId, const char *ExplTxt, int Dimen, int Typ, + int UserInfo, const int *MinUELIndices, const int *MaxUELIndices ) +{ + if( !PrepareSymbolWrite( "DataWriteRawStart"s, SyId, ExplTxt, Dimen, Typ, UserInfo ) ) return false; + // we overwrite the initialization + std::memcpy(MinElem.data(), MinUELIndices, sizeof(int)*FCurrentDim); + std::memcpy(MaxElem.data(), MaxUELIndices, sizeof(int)*FCurrentDim); + InitDoWrite( -1 ); + fmode = fw_dom_raw; + return true; +} + int TGXFileObj::gdxErrorCount() const { return ErrCntTotal; @@ -2277,7 +2297,7 @@ int TGXFileObj::gdxGetSpecialValues( double *AVals ) std::array svNames { "undef"s, "na"s, "posinf"s, "min"s, "eps"s }; std::array svIndices { sv_valund, sv_valna, sv_valpin, sv_valmin, sv_valeps }; for( int i = 0; i < (int) svNames.size(); i++ ) - std::cout << svNames[i] << "="s << AVals[svIndices[i]] << '\n'; + debugStream << svNames[i] << "="s << AVals[svIndices[i]] << '\n'; } return true; @@ -2299,7 +2319,7 @@ int TGXFileObj::gdxSetSpecialValues( const double *AVals ) std::array svNames { "undef"s, "na"s, "posinf"s, "min"s, "eps"s }; std::array svIndices { sv_valund, sv_valna, sv_valpin, sv_valmin, sv_valeps }; for( int i = 0; i < (int) svNames.size(); i++ ) - std::cout << svNames[i] << "="s << AVals[svIndices[i]] << '\n'; + debugStream << svNames[i] << "="s << AVals[svIndices[i]] << '\n'; } TIntlValueMapI64 tmpI64; @@ -2326,11 +2346,11 @@ int TGXFileObj::gdxSetSpecialValues( const double *AVals ) if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "Read dump, readIntlValueMapDbl\n"; + debugStream << "Read dump, readIntlValueMapDbl\n"; std::array svNames { "undef"s, "na"s, "posinf"s, "min"s, "eps"s }; std::array svIndices { sv_valund, sv_valna, sv_valpin, sv_valmin, sv_valeps }; for( int i = 0; i < (int) svNames.size(); i++ ) - std::cout << svNames[i] << "="s << readIntlValueMapDbl[svIndices[i]] << '\n'; + debugStream << svNames[i] << "="s << readIntlValueMapDbl[svIndices[i]] << '\n'; } intlValueMapI64 = tmpI64; @@ -2379,14 +2399,14 @@ int TGXFileObj::gdxSymbolGetDomainX( int SyNr, char **DomainIDs ) if( verboseTrace && TraceLevel == TraceLevels::trl_all && utils::in( res, 2, 3 ) ) { // NOTE: Not covered by unit tests yet. - std::cout << "GetDomain SyNr="s << SyNr << '\n'; + debugStream << "GetDomain SyNr="s << SyNr << '\n'; for( int D {}; D < SyPtr->SDim; D++ ) { if( res == 2 ) - std::cout << "SDomStrings["s << D << "]="s << SyPtr->SDomStrings[D] << '\n'; + debugStream << "SDomStrings["s << D << "]="s << SyPtr->SDomStrings[D] << '\n'; else if( res == 3 ) - std::cout << "SDomSymbols["s << D << "]="s << SyPtr->SDomSymbols[D] << '\n'; - std::cout << "DomainIDs["s << D << "]="s << DomainIDs[D] << '\n'; + debugStream << "SDomSymbols["s << D << "]="s << SyPtr->SDomSymbols[D] << '\n'; + debugStream << "DomainIDs["s << D << "]="s << DomainIDs[D] << '\n'; } } @@ -2432,9 +2452,9 @@ int TGXFileObj::gdxSymbolSetDomain( const char **DomainIDs ) if( verboseTrace && TraceLevel == TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "SetDomain\n"s; + debugStream << "SetDomain\n"s; for( int D {}; D < CurSyPtr->SDim; D++ ) - std::cout << "DomainID["s << D << "]="s << DomainIDs[D] << '\n'; + debugStream << "DomainID["s << D << "]="s << DomainIDs[D] << '\n'; } int res { true }; @@ -2524,9 +2544,9 @@ int TGXFileObj::gdxSymbolSetDomainX( int SyNr, const char **DomainIDs ) if( verboseTrace && TraceLevel == TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "SetDomainX SyNr="s << SyNr << '\n'; + debugStream << "SetDomainX SyNr="s << SyNr << '\n'; for( int D {}; D < SyPtr->SDim; D++ ) - std::cout << "DomainID["s << D << "]="s << DomainIDs[D] << '\n'; + debugStream << "DomainID["s << D << "]="s << DomainIDs[D] << '\n'; } if( SyPtr->SDim > 0 ) @@ -2569,7 +2589,7 @@ int TGXFileObj::gdxUELRegisterDone() int TGXFileObj::gdxUELRegisterRaw( const char *Uel ) { if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) - std::cout << "Uel=" << Uel << '\n';// NOTE: Not covered by unit tests yet. + debugStream << "Uel=" << Uel << '\n';// NOTE: Not covered by unit tests yet. if( ( TraceLevel >= TraceLevels::trl_all || fmode != f_raw_elem ) && !CheckMode( "UELRegisterRaw"s, f_raw_elem ) ) return false;// NOTE: Not covered by unit tests yet. @@ -2705,11 +2725,11 @@ int TGXFileObj::gdxDataWriteMap( const int *KeyInt, const double *Values ) { // NOTE: Not covered by unit tests yet. if( !CheckMode( "DataWriteMap"s, fw_map_data ) ) return false; - std::cout << " Index ="; + debugStream << " Index ="; for( int D {}; D < FCurrentDim; D++ ) { - std::cout << " " << std::to_string( KeyInt[D] ); - if( D + 1 < FCurrentDim ) std::cout << ","; + debugStream << " " << std::to_string( KeyInt[D] ); + if( D + 1 < FCurrentDim ) debugStream << ","; } } for( int D {}; D < FCurrentDim; D++ ) @@ -2747,7 +2767,7 @@ int TGXFileObj::gdxUELRegisterMap( int UMap, const char *Uel ) { // NOTE: Not covered by unit tests yet. if( !CheckMode( "UELRegisterMap"s, f_map_elem ) ) return false; - std::cout << " Enter UEL: " << SV << " with number " << UMap << "\n"; + debugStream << " Enter UEL: " << SV << " with number " << UMap << "\n"; } if( ErrorCondition( GoodUELString( SV, svLen ), ERR_BADUELSTR ) || ErrorCondition( UELTable->AddUsrIndxNew( SV, svLen, UMap ) >= 0, ERR_UELCONFLICT ) ) return false; @@ -3184,7 +3204,7 @@ int TGXFileObj::gdxSetTraceLevel( int N, const char *s ) //!! GetStdHandle(STD_OUTPUT_HANDLE) <> INVALID_HANDLE_VALUE; if( TraceLevel > TraceLevels::trl_errors ) { - std::cout << std::endl; + debugStream << std::endl; WriteTrace( "Tracing at level "s + std::to_string( (int) TraceLevel ) ); } return true; @@ -3441,14 +3461,14 @@ int TGXFileObj::gdxSetReadSpecialValues( const double *AVals ) if( verboseTrace && TraceLevel >= TraceLevels::trl_all ) { // NOTE: Not covered by unit tests yet. - std::cout << "gdxSetReadSpecialValues, dump of readIntlValueMapDbl\n"; + debugStream << "gdxSetReadSpecialValues, dump of readIntlValueMapDbl\n"; static const std::array, 5> svNameIndexPairs { { { "undef"s, sv_valund }, { "na"s, sv_valna }, { "posinf"s, sv_valpin }, { "min"s, sv_valmin }, { "eps"s, sv_valeps } } }; for( const auto &[svName, svIndex]: svNameIndexPairs ) - std::cout << svName << "="s << readIntlValueMapDbl[svIndex] << '\n'; + debugStream << svName << "="s << readIntlValueMapDbl[svIndex] << '\n'; } return true; diff --git a/src/rebuildall.py b/src/rebuildall.py new file mode 100644 index 00000000..374d236a --- /dev/null +++ b/src/rebuildall.py @@ -0,0 +1,39 @@ +# In GDX directory: +# 1. "python -m venv venv" +# 2. "source venv/bin/activate" +# 3. "pip install -r requirements.txt" + +import os +import subprocess + +import yaml2doxy +import yaml2cwrap + +# Rebuild main header file (gdx.h) +yaml2doxy.generate_method_declarations( + 'gdxapi.yaml', + 'templates', + 'gdxheader.template.j2', + 'gdx.h' +) + +# Rebuild C wrapper around GDX object (gdxcwrap.hpp) +yaml2cwrap.generate_c_wrapper( + 'gdxapi.yaml', + 'templates', + 'cwrap.template.j2', + '../generated/gdxcwrap.hpp' +) + +# Rebuild OOP C++ wrapper around C API (gdxcppwrap.h) +yaml2cwrap.generate_c_wrapper( + 'gdxapi.yaml', + 'templates', + 'gdxcppwrap.template.j2', + '../generated/gdxcppwrap.h' +) + +# Rebuild gdxcc.{h,c} and gdxcclib.cpp +cmd = ('python src/apigenerator/src/mkapi.py' + + f' --apidef {os.getcwd()}/gdxapi.yaml --outputpath generated/ --output cc cpplib') +subprocess.run(cmd.split(' '), shell=False, cwd='../') \ No newline at end of file diff --git a/src/strhash.h b/src/strhash.h index 4eee003a..8bb76553 100644 --- a/src/strhash.h +++ b/src/strhash.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/templates/cwrap.template.j2 b/src/templates/cwrap.template.j2 index 4f1cb8df..c0126326 100644 --- a/src/templates/cwrap.template.j2 +++ b/src/templates/cwrap.template.j2 @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -44,6 +44,7 @@ extern "C" { #endif typedef struct TGXFileRec TGXFileRec_t; +typedef TGXFileRec_t* gdxHandle_t; typedef void( GDX_CALLCONV *TDataStoreProc_t )( const int Indx[], const double Vals[] ); typedef int( GDX_CALLCONV *TDataStoreExProc_t )( const int Indx[], const double Vals[], int DimFrst, void *Uptr ); @@ -137,6 +138,8 @@ GDX_INLINE {{ map_type(fobj|first, fvals.type) }}{{ fobj|first }}( TGXFileRec_t {{fp_decor(None, map_type(fobj|first, parm_vals.type))}}{{parm|first}}{% if not loop.last %}, {% endif %}{% endfor -%} {%- if fvals.parameters %}{{' '}}{% endif %}) { + {% if fobj|first in custom_bodies %}{{custom_bodies[fobj|first]}} + {% endif -%} return reinterpret_cast( pgx )->{{fobj|first}}( {%- for parm in fvals.parameters -%} {%- set parm_vals = parm.values()|first -%} @@ -180,4 +183,5 @@ GDX_INLINE void setCallByRef( TGXFileRec_t *TGXFile, const char *FuncName, int c #ifdef __cplusplus } -#endif \ No newline at end of file +#endif + diff --git a/src/templates/gdxcppwrap.template.j2 b/src/templates/gdxcppwrap.template.j2 index 37761bd7..f2523698 100644 --- a/src/templates/gdxcppwrap.template.j2 +++ b/src/templates/gdxcppwrap.template.j2 @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * -* Copyright (c) 2017-2023 GAMS Software GmbH -* Copyright (c) 2017-2023 GAMS Development Corp. +* Copyright (c) 2017-2024 GAMS Software GmbH +* Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -136,3 +136,4 @@ public: }; }// namespace gdx + diff --git a/src/templates/gdxheader.template.j2 b/src/templates/gdxheader.template.j2 index 91e86ef6..d15f77ca 100644 --- a/src/templates/gdxheader.template.j2 +++ b/src/templates/gdxheader.template.j2 @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -230,3 +230,4 @@ bool gdxGetDomainElements_DP_CallByRef {}, }; }// namespace gdx + diff --git a/src/tests/datastoragetests.cpp b/src/tests/datastoragetests.cpp index e37432ca..4e3f215d 100644 --- a/src/tests/datastoragetests.cpp +++ b/src/tests/datastoragetests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * -* Copyright (c) 2017-2023 GAMS Software GmbH -* Copyright (c) 2017-2023 GAMS Development Corp. +* Copyright (c) 2017-2024 GAMS Software GmbH +* Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/tests/delphidifftests.cpp b/src/tests/delphidifftests.cpp index 7b089447..0ae16075 100644 --- a/src/tests/delphidifftests.cpp +++ b/src/tests/delphidifftests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * -* Copyright (c) 2017-2023 GAMS Software GmbH -* Copyright (c) 2017-2023 GAMS Development Corp. +* Copyright (c) 2017-2024 GAMS Software GmbH +* Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -190,7 +190,7 @@ static void validateRecursively(const std::string &path) { // Writing lots of uels and symbols builds up tables which is lots of effort // just dumping raw records instead is very efficient -static void createBigGDXFile() { +/*static void createBigGDXFile() { std::string errMsg; gdx::TGXFileObj gdx{errMsg}; int errNr; @@ -211,7 +211,7 @@ static void createBigGDXFile() { gdx.gdxDataWriteDone(); gdx.gdxClose(); -} +}*/ static void readFileCpp(const std::string &fn) { if(std::any_of(skipFiles.begin(), skipFiles.end(), [&](const std::string &skipFile) { return ends_with(fn, skipFile); })) @@ -245,7 +245,7 @@ static void readFileCpp(const std::string &fn) { for(int n{}; n<=nsyms1; n++) { REQUIRE(gdx.gdxSymbolInfo(n, symName1.data(), syDim1, syTyp1)); REQUIRE_FALSE(gdx.gdxErrorCount()); - auto nvals = syTyp1 < dt_var ? 1 : GMS_VAL_MAX; + //auto nvals = syTyp1 < dt_var ? 1 : GMS_VAL_MAX; REQUIRE(gdx.gdxSymbolInfoX(n, recCnt1, userInfo1, explText1.data())); std::chrono::time_point last, start; last = start = std::chrono::system_clock::now(); @@ -306,7 +306,7 @@ static void readFileDelphi(const std::string &fn) { for(int n{}; n<=nsyms2; n++) { REQUIRE(gdxSymbolInfo(pgx, n, symName2.data(), &syDim2, &syTyp2)); REQUIRE_FALSE(::gdxErrorCount(pgx)); - auto nvals = syTyp2 < dt_var ? 1 : GMS_VAL_MAX; + //auto nvals = syTyp2 < dt_var ? 1 : GMS_VAL_MAX; REQUIRE(::gdxSymbolInfoX(pgx, n, &recCnt2, &userInfo2, explText2.data())); std::chrono::time_point last, start; last = start = std::chrono::system_clock::now(); @@ -357,7 +357,7 @@ static void readRecursivelyDelphiAndCpp(const std::string &path) { } } -static void totalRuntimeDelphiVsCpp() { +/*static void totalRuntimeDelphiVsCpp() { { auto start { std::chrono::system_clock::now() }; //readRecursivelyDelphi( R"(G:\Shared drives\GAMS Performance Suite\gdxfiles)" ); @@ -371,7 +371,7 @@ static void totalRuntimeDelphiVsCpp() { readRecursivelyCpp( R"(C:\dockerhome)" ); std::cout << "Elapsed time C++: "s << elapsed_time(start) << std::endl; } -} +}*/ TEST_CASE( "Read all contents of a GDX file with both GAMS 43 P3/Delphi-GDX and C++-GDX" ) { diff --git a/src/tests/doctestmain.cpp b/src/tests/doctestmain.cpp index 46e2e9f3..04f9c0aa 100644 --- a/src/tests/doctestmain.cpp +++ b/src/tests/doctestmain.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/tests/gdxtests.cpp b/src/tests/gdxtests.cpp index 79b6df36..28f6d230 100644 --- a/src/tests/gdxtests.cpp +++ b/src/tests/gdxtests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * -* Copyright (c) 2017-2023 GAMS Software GmbH -* Copyright (c) 2017-2023 GAMS Development Corp. +* Copyright (c) 2017-2024 GAMS Software GmbH +* Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -2553,4 +2553,29 @@ TEST_CASE( "Test option to map acronym indices to NaN" ) std::filesystem::remove(fn); } +TEST_CASE( "Test writing in raw mode with known UEL index bounds" ) +{ + const std::string fn {"narrowKeys.gdx"}; + testWrite(fn, [&](TGXFileObj &pgx) { + int uelNr; + REQUIRE(pgx.gdxUELRegisterStrStart()); + REQUIRE(pgx.gdxUELRegisterStr("alpha", uelNr)); + REQUIRE(pgx.gdxUELRegisterStr("beta", uelNr)); + REQUIRE(pgx.gdxUELRegisterStr("gamma", uelNr)); + REQUIRE(pgx.gdxUELRegisterDone()); + std::array minUelIndices {1, 1}, maxUelIndices {1, 3}; + REQUIRE(pgx.gdxDataWriteRawStartKeyBounds("i", "a small set", 2, dt_set, 0, minUelIndices.data(), maxUelIndices.data())); + std::array keys {}; + const std::array vals {}; + keys.front() = 1; + for(int i{}; i<3; i++) + { + keys[1] = i+1; + REQUIRE(pgx.gdxDataWriteRaw( keys.data(), vals.data() )); + } + REQUIRE(pgx.gdxDataWriteDone()); + }); + std::filesystem::remove(fn); +} + }// namespace gdx::tests::gdxtests diff --git a/src/tests/gdxtests.h b/src/tests/gdxtests.h index 1665c8c3..94695483 100644 --- a/src/tests/gdxtests.h +++ b/src/tests/gdxtests.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * -* Copyright (c) 2017-2023 GAMS Software GmbH -* Copyright (c) 2017-2023 GAMS Development Corp. +* Copyright (c) 2017-2024 GAMS Software GmbH +* Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/tests/gmsdatatests.cpp b/src/tests/gmsdatatests.cpp index 4f70af52..0b64514a 100644 --- a/src/tests/gmsdatatests.cpp +++ b/src/tests/gmsdatatests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/tests/gmsobjtests.cpp b/src/tests/gmsobjtests.cpp index 127e0d28..bdc27f06 100644 --- a/src/tests/gmsobjtests.cpp +++ b/src/tests/gmsobjtests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/tests/gxfiletests.cpp b/src/tests/gxfiletests.cpp index 5a9ac866..4e470bac 100644 --- a/src/tests/gxfiletests.cpp +++ b/src/tests/gxfiletests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * -* Copyright (c) 2017-2023 GAMS Software GmbH -* Copyright (c) 2017-2023 GAMS Development Corp. +* Copyright (c) 2017-2024 GAMS Software GmbH +* Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/tests/strhashtests.cpp b/src/tests/strhashtests.cpp index 329c64f4..9142f420 100644 --- a/src/tests/strhashtests.cpp +++ b/src/tests/strhashtests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/tests/utilstests.cpp b/src/tests/utilstests.cpp index 22267b3b..956e8a2f 100644 --- a/src/tests/utilstests.cpp +++ b/src/tests/utilstests.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/utils.cpp b/src/utils.cpp index c5128031..34dcf579 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/utils.h b/src/utils.h index 306a3992..023517a3 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,8 +1,8 @@ /* * GAMS - General Algebraic Modeling System GDX API * - * Copyright (c) 2017-2023 GAMS Software GmbH - * Copyright (c) 2017-2023 GAMS Development Corp. + * Copyright (c) 2017-2024 GAMS Software GmbH + * Copyright (c) 2017-2024 GAMS Development Corp. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/yaml2cwrap.py b/src/yaml2cwrap.py index 502b4002..f1a90d79 100644 --- a/src/yaml2cwrap.py +++ b/src/yaml2cwrap.py @@ -18,6 +18,16 @@ def fp_decor(t, s): return s +custom_bodies = { + 'gdxUMUelGet': + '''if(!UelMap) + { + int tmpUelMap; + return reinterpret_cast( pgx )->gdxUMUelGet(UelNr, Uel, tmpUelMap ); + }''' +} + + def generate_c_wrapper(input, template_folder, template, output): with open(input) as fp: obj = yaml.load(fp, Loader=yaml.FullLoader) @@ -28,7 +38,7 @@ def generate_c_wrapper(input, template_folder, template, output): env.globals['fp_decor'] = fp_decor template = env.get_template(template) with open(output, 'w') as fp: - fp.write(template.render(obj=obj, properties=yaml2doxy.nice_properties(obj))) + fp.write(template.render(obj=obj, properties=yaml2doxy.nice_properties(obj), custom_bodies=custom_bodies)) def main(): @@ -36,7 +46,7 @@ def main(): ap.add_argument('--input', type=str, default='gdxapi.yaml', help='YAML API definition input filename') ap.add_argument('--output', type=str, - default='cwrap.hpp', help='Output GDX C-API wrapper header filename') + default='gdxcwrap.hpp', help='Output GDX C-API wrapper header filename') ap.add_argument('--template', type=str, default='cwrap.template.j2', help='Name of Jinja2 template file') ap.add_argument('--template_folder', type=str, diff --git a/src/yaml2doxy.py b/src/yaml2doxy.py index 10a7c583..1ba1003d 100644 --- a/src/yaml2doxy.py +++ b/src/yaml2doxy.py @@ -101,7 +101,7 @@ def collect_groups(functions): gtf = {} for f in functions: for name, attrs in f.items(): - group = None if not 'group' in attrs else attrs['group'] + group = None if 'group' not in attrs else attrs['group'] if group and group not in groups: groups.append(group) if group in gtf: