summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-10 20:30:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2018-09-10 20:31:02 +0000
commit996426ab3ca5b6efdfe282183f93f98c40dc670b (patch)
tree08db542cd037f5577b508f74667bcd72eee16bf8
parentReleasing progress-linux version 0.13.0-3~dschinn1. (diff)
downloadlibixion-996426ab3ca5b6efdfe282183f93f98c40dc670b.zip
libixion-996426ab3ca5b6efdfe282183f93f98c40dc670b.tar.xz
Merging upstream version 0.14.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--AUTHORS3
-rw-r--r--ChangeLog578
-rw-r--r--Makefile.in20
-rw-r--r--README4
-rw-r--r--aclocal.m449
-rw-r--r--config.h.in9
-rwxr-xr-xconfigure1427
-rw-r--r--configure.ac23
-rwxr-xr-xdepcomp6
-rw-r--r--include/Makefile.in12
-rw-r--r--include/ixion/Makefile.am4
-rw-r--r--include/ixion/Makefile.in16
-rw-r--r--include/ixion/address.hpp144
-rw-r--r--include/ixion/address_iterator.hpp69
-rw-r--r--include/ixion/cell.hpp51
-rw-r--r--include/ixion/cell_listener_tracker.hpp41
-rw-r--r--include/ixion/column_store_type.hpp15
-rw-r--r--include/ixion/compute_engine.hpp66
-rw-r--r--include/ixion/config.hpp17
-rw-r--r--include/ixion/formula_function_opcode.hpp3
-rw-r--r--include/ixion/formula_result.hpp16
-rw-r--r--include/ixion/formula_tokens.hpp40
-rw-r--r--include/ixion/formula_tokens_fwd.hpp26
-rw-r--r--include/ixion/info.hpp3
-rw-r--r--include/ixion/interface/Makefile.in12
-rw-r--r--include/ixion/interface/formula_model_access.hpp6
-rw-r--r--include/ixion/matrix.hpp66
-rw-r--r--include/ixion/mem_str_buf.hpp2
-rw-r--r--include/ixion/model_context.hpp62
-rw-r--r--include/ixion/module.hpp35
-rw-r--r--include/ixion/types.hpp74
-rw-r--r--ltmain.sh4
-rw-r--r--m4/libtool.m41
-rw-r--r--src/Makefile.in12
-rw-r--r--src/ixion_formula_tokenizer.cpp5
-rw-r--r--src/libixion/Makefile.am60
-rw-r--r--src/libixion/Makefile.in263
-rw-r--r--src/libixion/address.cpp137
-rw-r--r--src/libixion/address_iterator.cpp316
-rw-r--r--src/libixion/calc_status.cpp29
-rw-r--r--src/libixion/calc_status.hpp56
-rw-r--r--src/libixion/cell.cpp276
-rw-r--r--src/libixion/cell_listener_tracker.cpp92
-rw-r--r--src/libixion/compute_engine.cpp76
-rw-r--r--src/libixion/compute_engine_cuda.cpp57
-rw-r--r--src/libixion/compute_engine_cuda.hpp28
-rw-r--r--src/libixion/compute_engine_test.cpp40
-rw-r--r--src/libixion/config.cpp11
-rw-r--r--src/libixion/constants.inl.in3
-rw-r--r--src/libixion/formula.cpp85
-rw-r--r--src/libixion/formula_functions.cpp173
-rw-r--r--src/libixion/formula_functions.hpp1
-rw-r--r--src/libixion/formula_interpreter.cpp40
-rw-r--r--src/libixion/formula_interpreter.hpp2
-rw-r--r--src/libixion/formula_lexer.cpp12
-rw-r--r--src/libixion/formula_lexer.hpp4
-rw-r--r--src/libixion/formula_name_resolver.cpp2
-rw-r--r--src/libixion/formula_result.cpp151
-rw-r--r--src/libixion/formula_tokens.cpp48
-rw-r--r--src/libixion/formula_value_stack.cpp55
-rw-r--r--src/libixion/formula_value_stack.hpp20
-rw-r--r--src/libixion/function_objects.cpp44
-rw-r--r--src/libixion/function_objects.hpp17
-rw-r--r--src/libixion/global.cpp24
-rw-r--r--src/libixion/grouped_ranges.cpp89
-rw-r--r--src/libixion/grouped_ranges.hpp59
-rw-r--r--src/libixion/info.cpp10
-rw-r--r--src/libixion/interface.cpp4
-rw-r--r--src/libixion/ixion_test.cpp100
-rw-r--r--src/libixion/ixion_test_track_deps.cpp142
-rw-r--r--src/libixion/matrix.cpp210
-rw-r--r--src/libixion/mem_str_buf.cpp14
-rw-r--r--src/libixion/model_context.cpp475
-rw-r--r--src/libixion/module.cpp75
-rw-r--r--src/libixion/types.cpp40
-rw-r--r--src/libixion/workbook.cpp6
-rw-r--r--src/libixion/workbook.hpp2
-rw-r--r--src/model_parser.cpp374
-rw-r--r--src/model_parser.hpp5
-rw-r--r--src/python/Makefile.in12
-rw-r--r--src/python/sheet.cpp18
81 files changed, 5303 insertions, 1375 deletions
diff --git a/AUTHORS b/AUTHORS
index 49247cb..a021f10 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,8 +1,9 @@
Kohei Yoshida <kohei.yoshida@gmail.com>
+Markus Mohrhard <markus.mohrhard@googlemail.com>
David Tardon <dtardon@redhat.com>
Cédric Bosdonnat <cedric.bosdonnat@free.fr>
-Markus Mohrhard <markus.mohrhard@googlemail.com>
Fridrich Štrba <fridrich.strba@bluewin.ch>
+Andreas Sturmlechner <andreas.sturmlechner@gmail.com>
Andreas Schwab <schwab@linux-m68k.org>
Bjoern Michaelsen <bjoern.michaelsen@canonical.com>
Miklos Vajna <vmiklos@frugalware.org>
diff --git a/ChangeLog b/ChangeLog
index 501ebc5..496f75f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,583 @@
# Generated by Makefile. Do not edit.
+commit dbb229782d26e256819b8e81006f4fa72ad1fb9e
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Aug 22 20:11:33 2018 -0400
+
+ Actually there is API incompatible change. Bumping up the API version.
+
+commit 934179c0365151d9555dbbda200877ee89792f9a
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Aug 22 20:01:29 2018 -0400
+
+ Add URL's to the 0.14.0 packages.
+
+commit 4d3075c04e4bda15bbff18ba2179424519eab71d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Aug 22 18:33:16 2018 -0400
+
+ Up the version to 0.14.0.
+
+commit e436596999557e18fecd2536d544c056c3596c65
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Aug 21 22:13:05 2018 -0400
+
+ mdds 1.4.0 is released.
+
+commit 06837d2b084bb4024eb105f9a1402a42697d3016
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Jun 12 22:27:45 2018 -0400
+
+ It now depends on the master branch of mdds.
+
+commit 603729483b2c167f283c5383d35e4a7ce174c8d1
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Apr 16 18:39:50 2018 -0400
+
+ The gettimeofday call is no longer used.
+
+commit 18f62b00f17dfd794c3bcfe23a18a124b0238d6a
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Apr 16 18:29:10 2018 -0400
+
+ Use cross-platform way to query seconds since epoch.
+
+commit 2719761a74396021ac911c89c12d092978186f69
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Apr 16 18:16:14 2018 -0400
+
+ There is no need to append an extra character like this.
+
+commit bb09b2a2522d78660c26b75282a4ebf0936a112c
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Apr 9 17:22:35 2018 -0400
+
+ Make get_single_result_cache() -> get_result_cache().
+
+ This method should be the primary method to be called to get a
+ formula result.
+
+commit e477bd775e8ded376760b37c807a13ec299b65b7
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sun Apr 8 21:20:18 2018 -0400
+
+ Add new changes.
+
+commit be91d1b029064f8bad829379aa424f0e15de9657
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sun Apr 8 20:14:18 2018 -0400
+
+ Add a boolean 'grouped' member to formula_group_t.
+
+commit 5c8af00f910b1cf68ce2a11bc027edd0604328ee
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sun Apr 8 20:07:49 2018 -0400
+
+ Add a method to determine the parent position of a group.
+
+commit 5e128e40f5918907e2d0934c1450569f8ad183fa
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Apr 4 18:17:55 2018 -0400
+
+ Change the wording for clarity.
+
+ * whole_column -> all_columns
+ * whole_row -> all_rows
+
+commit fe7fe672c339493f1032cf1285188d4408adb5f7
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Apr 2 20:53:25 2018 -0400
+
+ Revert "Use the grouped range to move the listening destination."
+
+ This reverts commit 401231d770591a3fd6619a7c31aa8cee823a88a4.
+
+commit 401231d770591a3fd6619a7c31aa8cee823a88a4
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Apr 2 20:35:06 2018 -0400
+
+ Use the grouped range to move the listening destination.
+
+ In case the listening destination cell is within a grouped range,
+ move to its origin position (top-left cell) for the purpose of
+ tracking dependencies.
+
+commit 817396a1bda3082ad41534ea65047db7c66e6faf
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Apr 2 18:36:25 2018 -0400
+
+ Re-implement grouped_range with rectangle_set.
+
+ flat_segment_tree wouldn't have worked since two goruped ranges may
+ still overlap by either column or row direction without them actually
+ overlapping with each other.
+
+commit 7a4066b617efddcdac68b315048f947e2517d34b
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Mar 31 09:41:12 2018 -0400
+
+ Store group size with the calc_status instance.
+
+ And add a method to formula cell that returns formula group
+ properties.
+
+ This commit also renames sheet_size_t to rc_size_t, to make it sound
+ more generic and be usable in other areas.
+
+commit eb29194b87a7ad73b01a0c0e377af8d2042830a8
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Fri Mar 30 22:49:43 2018 -0400
+
+ Keep track of grouped ranges so that we can find their origins.
+
+commit 0c64338400e823dc7cfa67647a7eaf91032d84c9
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 29 20:39:35 2018 -0400
+
+ Remove unused method.
+
+ I don't think there is any value keeping this method around.
+
+commit 158699bdaf8ea17634a07e320605455f07e3b143
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 29 19:32:05 2018 -0400
+
+ Use ranged for loop and remove unused function object.
+
+commit 5c10772ae03f9e2b4f1d4c801d079b6d4d3aaf6e
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 29 19:14:42 2018 -0400
+
+ Fix a bug in get_all_dirty_cells().
+
+ * C5 listens to A1:C1.
+ * A10 listens to C5.
+
+ When A1 gets modified, the old code would only return C5 as its
+ dependent, but it should actually return both C5 and A10. This change
+ fixes it.
+
+commit 62f4d060dd071357dba0b7ba1de6592b0855aa2b
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 28 23:10:22 2018 -0400
+
+ Add a separate test program for dependency tracking.
+
+ Currently range tracking isn't working. I need to look into this.
+
+commit 85cf3b39cdcf1bf30aea66971349568ef6ef58e7
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 28 21:57:29 2018 -0400
+
+ Be more descriptive.
+
+commit e91f61cb44ad39021a805c009d7ec5a13034eb8d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 28 21:44:49 2018 -0400
+
+ Retrieve a single numeric value from a matrix result.
+
+commit 62f46e18c0eafd9e17511b4d5ebe72825ecf4ee1
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 28 20:08:59 2018 -0400
+
+ Check for re-calculation as well.
+
+commit 4f6245bb0b28ff59bbf18edb52fbee0d4904d09f
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 28 19:59:19 2018 -0400
+
+ Add a function that always returns a single cell result value.
+
+ And use it when validating formula cell calculation results. With
+ this, now we can enable the MMULT function calculation test which
+ returns a matrix result.
+
+commit 1bfabe2e2663946028ced59db57cfb9cb89da128
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 27 21:46:30 2018 -0400
+
+ Add some rudimentary test for matrix and numeric_matrix.
+
+commit c421a8413f1cbd378810280c3e9deefb65f5ad4b
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 27 20:32:56 2018 -0400
+
+ Make nuemric_matrix column-major.
+
+ Since the matrix class is column-major, we need to make
+ numeric_matrix also column-major as well, else it would transepose
+ the content when being passed to the matrix constructor.
+
+commit c03353d24078f8b5d790336b4046cbdcef80fece
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 27 20:28:00 2018 -0400
+
+ Print out the matrix result for real.
+
+commit 5e1b7103e10e1aef0a3a597eb3fd86dc85a21e00
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Mar 26 21:34:07 2018 -0400
+
+ Remove unused & non-functional class.
+
+commit 42934079d6a3741c56dfb482c6ccb4b700ce9014
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Mar 26 21:31:13 2018 -0400
+
+ Get the matrix formula cell to calculate & fix the display string.
+
+commit 790c5d97ca25ff9683a3acdfedbcaa4c18abe3f1
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Mar 26 21:15:33 2018 -0400
+
+ Finally manage to insert grouped formula cells for matrix values.
+
+ Still not working fully yet.
+
+commit e1177987476fae59ba0ed4428da500b0b9bbc197
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Mar 26 18:38:43 2018 -0400
+
+ Discover and parse matrix formula definitions.
+
+ Matrix cells are not yet created.
+
+commit c7023be5b6afb55f24f9c93fafb985883f349a9d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Mar 24 13:30:15 2018 -0400
+
+ Add test case for ranged definitions with duplicate values.
+
+commit d4b11e8967890947ebcb02072e3b59ebae2527fe
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Mar 24 12:49:45 2018 -0400
+
+ Support iterating in either horizontal or vertical direction.
+
+commit fe5e0c3d13465339c83493c03b55bc921129d477
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Mar 24 11:18:44 2018 -0400
+
+ Add iterator for absolute address ranges.
+
+ And use it to iterate through cells within range.
+
+commit 320f7026c64492d970bc437189ce9b2dfb8a0eb9
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Fri Mar 23 22:28:31 2018 -0400
+
+ Work on supporting assignment to cell range.
+
+ The goal is to let you do things like:
+
+ {A1:C3}=1
+
+ to mass-assign the same value to multiple cells which in this case
+ is A1:C3. Not finished yet.
+
+commit f825b566f7eed096d0a1d86a28bfa5dbe01e0402
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Fri Mar 23 20:01:11 2018 -0400
+
+ Remove non-buildable debug statement code.
+
+commit 6b02023e674424dd22df2d7911f712c6b1fb6bdf
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 22 17:43:45 2018 -0400
+
+ Stack is LIFO, not FIFO.
+
+commit fcdaa998f94a243f599b3cc2023a7aa8985f5a88
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 21 21:20:49 2018 -0400
+
+ Add the ability to store matrix result to formula cell.
+
+commit f83adb060523ac41bfb140a46d8b92e7a40b14b5
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 21 19:53:04 2018 -0400
+
+ Add these files to slickedit project.
+
+commit 21c2a34c2226586fab4a242eca13ab6d2e7d66a3
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Wed Mar 21 18:39:22 2018 -0400
+
+ Share single calc_status instance amongst all grouped cells.
+
+commit a062604d5df1fb691f0e2ee03ea78daad3d55a6c
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 20 22:35:14 2018 -0400
+
+ Add a class that manages creation of grouped formula cells.
+
+ I still need to work on sharing the calc status object amongst the
+ grouped cells.
+
+commit ea5770cb1ca2e3a8313b00fc528dbe0b7f7bd488
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 20 21:22:18 2018 -0400
+
+ Make sure we calculate only the top-left cell of a group.
+
+ Of course if it's not grouped, it's okay to calculate.
+
+commit d3186c61746b5d2686e1645488650ff60b59388d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 20 21:15:21 2018 -0400
+
+ Reduce the amount of dereferencing.
+
+commit 68ff9546747556030b31173ec78a69c9050f8596
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 20 20:46:35 2018 -0400
+
+ Rename interpret_status to calc_status. Easier to type.
+
+commit 84675c852edac57b9be4ab097132785799e9bb07
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 20 19:30:44 2018 -0400
+
+ Preparing formula_cell to be groupable...
+
+ Store group position info, and make the interpret_status object
+ shareable.
+
+commit 804f13bcea5f0a7a25820791f30a219368f9d07c
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Mar 19 22:06:20 2018 -0400
+
+ Disambiguate make_unique.
+
+commit 03b4c383f2094566694b2d5307c072988944e0cd
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Mar 19 21:55:59 2018 -0400
+
+ Push matrix result onto the value stack.
+
+commit 94813f3bad6bb9f1700d5f9416965dd3b05e169d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Mar 19 21:12:52 2018 -0400
+
+ Implement MMULT partially.
+
+ Only the top-left matrix value is returned as the result for now.
+
+commit ac52c79fba6251f9f2a51f1b3858ec7d1c63f883
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Fri Mar 16 21:27:09 2018 -0400
+
+ Add function hook for MMULT.
+
+ I have yet to properly implement this function.
+
+commit 95685e1986a0fe64f76e2e6f88cd7cb2103c7ecb
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Fri Mar 16 18:18:32 2018 -0400
+
+ Rename get_store() to just get().
+
+commit ad384af0a7ca768bb8a538d630389c632d3abc87
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 22:02:03 2018 -0400
+
+ We don't need this struct now.
+
+commit 67de163f742cff925766137ea76bd48b837b24ec
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 21:56:28 2018 -0400
+
+ Use std::unique_ptr for this.
+
+commit 1964aa6b90c8fef7f993984651aef53076cac5a0
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 21:42:47 2018 -0400
+
+ Add a variant of set_formula_cell() that takes shared formula tokens.
+
+commit 194de0da5ed511ccaca2a85874bb85c997d74668
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 21:25:11 2018 -0400
+
+ Change set_formula_cell() to take formula_tokens_t instead.
+
+commit 4dba364ccda347823b7c920faf5b56acc7d9df47
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 20:41:53 2018 -0400
+
+ No more separate tokens storage with model_context.
+
+commit 2df2be51a49602cc09e7733c1dda0f4ecac7a6f2
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 20:19:37 2018 -0400
+
+ No more shared flag in formula_cell.
+
+commit 5caa380f9c8481bcac9914955778afa48f43982f
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 20:17:53 2018 -0400
+
+ Remove identifer storage from formula_cell, and get it working.
+
+commit 7b138c958ac9d16997941e4e324e14091baf7e62
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Thu Mar 15 18:49:57 2018 -0400
+
+ This method doesn't need to be in the interface.
+
+commit e6247cb934abff67f30ee9c024f605de08fe7a93
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 13 22:28:11 2018 -0400
+
+ Getter is const. Also let's return a const reference instead.
+
+commit 53e6ba8587a6f454eb4233ff013af0ec8bf04284
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 13 21:25:34 2018 -0400
+
+ Make the formula_tokens_store's pointer type forward-declareable.
+
+ And add setter and ctor for this in formula_cell.
+
+commit d3c70591b3e7d49cfa2bde2fb38b7e5d05f49641
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 13 19:26:00 2018 -0400
+
+ Let's not forget to add a way to get the actual tokens.
+
+commit 3ebb94cf06dffcd01a4d1fa76f9366f1f7a46c28
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 13 19:18:14 2018 -0400
+
+ Add a staic create() method and write some test code on ref-counting.
+
+commit 6fd3a15cc58346582584f00d7979e2fe7be14d27
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Mar 13 18:55:28 2018 -0400
+
+ Add a new class to store ref-counted formula tokens.
+
+ Not used or tested yet.
+
+commit 14101da22a1bdf2238783c4a9dd6c334ff2706f7
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Feb 19 10:57:12 2018 -0500
+
+ Support configuration option for output precision.
+
+commit ea8a160b021494d59fc9add18537bf95151b57a0
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Feb 12 18:24:52 2018 -0500
+
+ Do actually make use of the argument separator specified in the config.
+
+commit a0df598f829864cf346de7c1fad4d0b2feeec23c
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Feb 10 11:58:13 2018 -0500
+
+ Add a test case for the built-in CONCATENATE function.
+
+commit 2ae3fa659555f1a90ee0a37e2194416e3a0f0cfd
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Feb 6 22:17:30 2018 -0500
+
+ Up the version to a development version.
+
+commit 32ee682a379e1626f5f5a06765fa67504ca20cfe
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Feb 6 22:09:32 2018 -0500
+
+ This part is not cross-platform. Conditionalize it against _WIN32.
+
+commit cefe6073242891a74aeaab3c5ffa3f0ecad182cf
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Feb 6 21:59:15 2018 -0500
+
+ Put the compute engine and related code under 'draft' namespace.
+
+ They are still largely experimental.
+
+commit 381484fcce806bc6d5742bb548b0c3343147130d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Feb 6 21:48:51 2018 -0500
+
+ Let's call the default compute engine "default" instead of "base".
+
+commit edf79aa57df59488a1202764389620e497523d15
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Feb 5 18:46:14 2018 -0500
+
+ Add --enable-cuda build option to enable/disable CUDA compute engine.
+
+commit c928f23e5037c8352fa85b29c5eebb4a723df94d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Nov 28 20:29:38 2017 -0500
+
+ Use boost filesystem for real.
+
+commit 26832e00afafbfa97c078765178e20d1ce9fcac2
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Nov 28 18:53:34 2017 -0500
+
+ Change it so that new module types can be added later.
+
+commit 392458df4d8fa119408e53eb9969ad4e6f5ad24d
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Nov 27 20:23:50 2017 -0500
+
+ Avoid hard-coding the API version string.
+
+commit e95147daeecf04a8db1e74649c93f8f8e6d2bd92
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Nov 20 21:12:36 2017 -0500
+
+ Add class and method docs.
+
+commit a02450f9de44b0964851f2e44a75eb8cf4ba2b38
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Mon Nov 20 20:57:48 2017 -0500
+
+ Store the create/destroy function pointers for compute_engine classes.
+
+commit 59e6d0ea6ec956177412c04cc6f8f8dd2ce1e1ac
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Nov 18 22:38:40 2017 -0500
+
+ Get module definition data from the cuda module.
+
+commit b9c8815a28436bbdaa3e427a0e90d33426d15692
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Nov 18 21:06:49 2017 -0500
+
+ Set up a test environment for the new compute_engine class.
+
+commit cabbb69afbbed81a2e8b5346893ae540f305d5ea
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sat Nov 18 18:59:36 2017 -0500
+
+ Use nullptr.
+
+commit a00f1c8c39ca136eb4dd4b686318dc303ddcf75e
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Sun Oct 8 21:42:49 2017 -0400
+
+ Remove obsolete Visual Studio solution files.
+
+ Use cmake instead.
+
+commit 2aa13f6f281da3dda38046d5df9ba44b504a493a
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Aug 15 20:54:48 2017 -0400
+
+ Update the authors list.
+
+commit b4f8fb210e389844a488be843fdc13ddd258d62e
+Author: Kohei Yoshida <kohei.yoshida@gmail.com>
+Date: Tue Aug 15 19:34:52 2017 -0400
+
+ Add URL's to the 0.13.0 packages.
+
commit 789a08ebc3e7fc2a3914fc34b2497bf476952bfc
Author: Kohei Yoshida <kohei.yoshida@gmail.com>
Date: Tue Aug 15 19:18:03 2017 -0400
diff --git a/Makefile.in b/Makefile.in
index 56d6852..2023dc3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -247,11 +247,17 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
BOOST_LDPATH = @BOOST_LDPATH@
BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
@@ -282,8 +288,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IXION_API_VERSION = @IXION_API_VERSION@
+IXION_MAJOR_API_VERSION = @IXION_MAJOR_API_VERSION@
IXION_MAJOR_VERSION = @IXION_MAJOR_VERSION@
IXION_MICRO_VERSION = @IXION_MICRO_VERSION@
+IXION_MINOR_API_VERSION = @IXION_MINOR_API_VERSION@
IXION_MINOR_VERSION = @IXION_MINOR_VERSION@
IXION_VERSION = @IXION_VERSION@
LD = @LD@
@@ -725,7 +733,7 @@ distdir: $(DISTFILES)
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r "$(distdir)"
dist-gzip: distdir
- tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
$(am__post_remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
@@ -749,7 +757,7 @@ dist-shar: distdir
@echo WARNING: "Support for shar distribution archives is" \
"deprecated." >&2
@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
- shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
$(am__post_remove_distdir)
dist-zip: distdir
@@ -767,7 +775,7 @@ dist dist-all:
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.lz*) \
@@ -777,7 +785,7 @@ distcheck: dist
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
- GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
diff --git a/README b/README
index 1a24d4e..4a022d6 100644
--- a/README
+++ b/README
@@ -59,6 +59,10 @@ for both full and partial calculation modes.
| Version | API Version | Release Date | Download | Check Sum | File Size (bytes) |
|---------|-------------|--------------|----------|-----------|-------------------|
+| 0.14.0 | 0.13 | 2018-08-22 | [libixion-0.14.0.tar.xz](http://kohei.us/files/ixion/src/libixion-0.14.0.tar.xz) | sha256sum: 3af203805fe4511b4ce3ca01b8ffeafe0927d3fdda03b69c82fe58a0d1e8b454 | 426900 |
+| | | | [libixion-0.14.0.tar.gz](http://kohei.us/files/ixion/src/libixion-0.14.0.tar.gz) | sha256sum: dc0e6a01ee1364c351b7b98fb190c6a409e6c5eb9ae2d7d278a942ff4444be84 | 636751 |
+| 0.13.0 | 0.13 | 2017-08-15 | [libixion-0.13.0.tar.xz](http://kohei.us/files/ixion/src/libixion-0.13.0.tar.xz) | sha256sum: 5ae360c52ba2d17c4abf5ae21fa947f75925459e085acef5972395f77333c7e5 | 413756 |
+| | | | [libixion-0.13.0.tar.gz](http://kohei.us/files/ixion/src/libixion-0.13.0.tar.gz) | sha256sum: f990c18354a5aaa7e2a99a38c44f37f8169aa86a54bf285be26e21453fae3b8b | 636751 |
| 0.12.2 | 0.12 | 2016-12-14 | [libixion-0.12.2.tar.xz](http://kohei.us/files/ixion/src/libixion-0.12.2.tar.xz) | sha256sum: 8b44008836bb4e1a3dff4d3e40afec6c73037e3518e72cc85b5cc675fbc2daae | 407280 |
| | | | [libixion-0.12.2.tar.gz](http://kohei.us/files/ixion/src/libixion-0.12.2.tar.gz) | sha256sum: 00d7a44f3d8266fd7da46ceb336288f77fc57bdd95402bdc9bb95f1dcb883baf | 627147 |
| 0.12.1 | 0.12 | 2016-09-17 | [libixion-0.12.1.tar.xz](http://kohei.us/files/ixion/src/libixion-0.12.1.tar.xz) | sha256sum: 000820ba51109ec21cbdb7ea83c1fdb0acbcfeb55b4a6a80fe02b71d45c587c2 | 406300 |
diff --git a/aclocal.m4 b/aclocal.m4
index 1b1e419..994ff0b 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.15 -*- Autoconf -*-
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -296,7 +296,7 @@ AS_VAR_COPY([$1], [pkg_cv_][$1])
AS_VAR_IF([$1], [""], [$5], [$4])dnl
])dnl PKG_CHECK_VAR
-# Copyright (C) 2002-2014 Free Software Foundation, Inc.
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -311,7 +311,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.15'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
-m4_if([$1], [1.15], [],
+m4_if([$1], [1.15.1], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@@ -327,14 +327,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.15])dnl
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -386,7 +386,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
# AM_CONDITIONAL -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -417,7 +417,7 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]])
fi])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -608,7 +608,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl
# Generate code to set up dependency tracking. -*- Autoconf -*-
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -684,7 +684,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
# Do all the work for Automake. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -881,7 +881,7 @@ for _am_header in $config_headers :; do
done
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -902,7 +902,7 @@ if test x"${install_sh+set}" != xset; then
fi
AC_SUBST([install_sh])])
-# Copyright (C) 2003-2014 Free Software Foundation, Inc.
+# Copyright (C) 2003-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -923,7 +923,7 @@ AC_SUBST([am__leading_dot])])
# Check to see how 'make' treats includes. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -973,7 +973,7 @@ rm -f confinc confmf
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
-# Copyright (C) 1997-2014 Free Software Foundation, Inc.
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1012,7 +1012,7 @@ fi
# Helper functions for option handling. -*- Autoconf -*-
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1041,7 +1041,7 @@ AC_DEFUN([_AM_SET_OPTIONS],
AC_DEFUN([_AM_IF_OPTION],
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1088,7 +1088,7 @@ AC_LANG_POP([C])])
# For backward compatibility.
AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1121,8 +1121,9 @@ AC_DEFUN([AM_PATH_PYTHON],
[
dnl Find a Python interpreter. Python versions prior to 2.0 are not
dnl supported. (2.0 was released on October 16, 2000).
+ dnl FIXME: Remove the need to hard-code Python versions here.
m4_define_default([_AM_PYTHON_INTERPRETER_LIST],
-[python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
+[python python2 python3 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 dnl
python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0])
AC_ARG_VAR([PYTHON], [the Python interpreter])
@@ -1323,7 +1324,7 @@ for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]]
sys.exit(sys.hexversion < minverhex)"
AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1342,7 +1343,7 @@ AC_DEFUN([AM_RUN_LOG],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
-# Copyright (C) 1996-2014 Free Software Foundation, Inc.
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1423,7 +1424,7 @@ AC_CONFIG_COMMANDS_PRE(
rm -f conftest.file
])
-# Copyright (C) 2009-2014 Free Software Foundation, Inc.
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1483,7 +1484,7 @@ AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
-# Copyright (C) 2001-2014 Free Software Foundation, Inc.
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1511,7 +1512,7 @@ fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
-# Copyright (C) 2006-2014 Free Software Foundation, Inc.
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -1530,7 +1531,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
-# Copyright (C) 2004-2014 Free Software Foundation, Inc.
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
diff --git a/config.h.in b/config.h.in
index 2ca7d17..4cb7761 100644
--- a/config.h.in
+++ b/config.h.in
@@ -3,18 +3,21 @@
/* Defined if the requested minimum BOOST version is satisfied */
#undef HAVE_BOOST
+/* Define to 1 if you have <boost/filesystem/path.hpp> */
+#undef HAVE_BOOST_FILESYSTEM_PATH_HPP
+
/* Define to 1 if you have <boost/program_options.hpp> */
#undef HAVE_BOOST_PROGRAM_OPTIONS_HPP
+/* Define to 1 if you have <boost/system/error_code.hpp> */
+#undef HAVE_BOOST_SYSTEM_ERROR_CODE_HPP
+
/* define if the compiler supports basic C++11 syntax */
#undef HAVE_CXX11
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
-/* Define to 1 if you have the `gettimeofday' function. */
-#undef HAVE_GETTIMEOFDAY
-
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
diff --git a/configure b/configure
index 151b8d2..340ebce 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libixion 0.13.0.
+# Generated by GNU Autoconf 2.69 for libixion 0.14.0.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='libixion'
PACKAGE_TARNAME='libixion'
-PACKAGE_VERSION='0.13.0'
-PACKAGE_STRING='libixion 0.13.0'
+PACKAGE_VERSION='0.14.0'
+PACKAGE_STRING='libixion 0.14.0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -632,11 +632,12 @@ ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
LTLIBOBJS
BOOST_PROGRAM_OPTIONS_LIBS
-BOOST_LDPATH
BOOST_PROGRAM_OPTIONS_LDPATH
BOOST_PROGRAM_OPTIONS_LDFLAGS
OSX_FALSE
OSX_TRUE
+BUILD_CUDA_FALSE
+BUILD_CUDA_TRUE
IXION_THREADS_FALSE
IXION_THREADS_TRUE
BUILD_PYTHON_FALSE
@@ -657,6 +658,13 @@ MDDS_CFLAGS
PKG_CONFIG_LIBDIR
PKG_CONFIG_PATH
PKG_CONFIG
+BOOST_FILESYSTEM_LIBS
+BOOST_FILESYSTEM_LDPATH
+BOOST_FILESYSTEM_LDFLAGS
+BOOST_SYSTEM_LIBS
+BOOST_LDPATH
+BOOST_SYSTEM_LDPATH
+BOOST_SYSTEM_LDFLAGS
BOOST_CPPFLAGS
DISTCHECK_CONFIGURE_FLAGS
BOOST_ROOT
@@ -693,6 +701,8 @@ LIBTOOL
OBJDUMP
DLLTOOL
AS
+IXION_MINOR_API_VERSION
+IXION_MAJOR_API_VERSION
IXION_MICRO_VERSION
IXION_MINOR_VERSION
IXION_MAJOR_VERSION
@@ -797,6 +807,7 @@ enable_silent_rules
enable_dependency_tracking
enable_python
enable_threads
+enable_cuda
enable_static
with_pic
enable_shared
@@ -806,8 +817,8 @@ with_gnu_ld
with_sysroot
enable_libtool_lock
with_boost
-enable_debug
enable_static_boost
+enable_debug
'
ac_precious_vars='build_alias
host_alias
@@ -1382,7 +1393,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures libixion 0.13.0 to adapt to many kinds of systems.
+\`configure' configures libixion 0.14.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1453,7 +1464,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of libixion 0.13.0:";;
+ short | recursive ) echo "Configuration of libixion 0.14.0:";;
esac
cat <<\_ACEOF
@@ -1469,14 +1480,15 @@ Optional Features:
speeds up one-time build
--disable-python Disable python bindings
--disable-threads Disable threaded calculations
+ --enable-cuda Enable CUDA compute engine
--enable-static[=PKGS] build static libraries [default=no]
--enable-shared[=PKGS] build shared libraries [default=yes]
--enable-fast-install[=PKGS]
optimize for fast installation [default=yes]
--disable-libtool-lock avoid locking (might break parallel builds)
- --enable-debug Build with debug features in mind.]
--enable-static-boost Prefer the static boost libraries over the shared
ones [no]
+ --enable-debug Build with debug features in mind.]
Optional Packages:
--with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
@@ -1584,7 +1596,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-libixion configure 0.13.0
+libixion configure 0.14.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2211,7 +2223,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by libixion $as_me 0.13.0, which was
+It was created by libixion $as_me 0.14.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3076,7 +3088,7 @@ fi
# Define the identity of the package.
PACKAGE='libixion'
- VERSION='0.13.0'
+ VERSION='0.14.0'
cat >>confdefs.h <<_ACEOF
@@ -4251,7 +4263,7 @@ case $host_os in
;;
*)
_os=
- LDFLAGS="$LDFLAGS -Wl,--no-as-needed -pthread"
+ LDFLAGS="$LDFLAGS -Wl,--no-as-needed -pthread -ldl"
;;
esac
@@ -4273,11 +4285,24 @@ else
fi
-IXION_VERSION=0.13.0
-IXION_API_VERSION=0.13
+# Check whether --enable-cuda was given.
+if test "${enable_cuda+set}" = set; then :
+ enableval=$enable_cuda; enable_cuda="$enableval"
+else
+ enable_cuda=no
+
+fi
+
+
+IXION_VERSION=0.14.0
+IXION_API_VERSION=0.14
IXION_MAJOR_VERSION=0
-IXION_MINOR_VERSION=13
+IXION_MINOR_VERSION=14
IXION_MICRO_VERSION=0
+IXION_MAJOR_API_VERSION=0
+IXION_MINOR_API_VERSION=14
+
+
@@ -17330,17 +17355,6 @@ fi
fi
-for ac_func in gettimeofday
-do :
- ac_fn_c_check_func "$LINENO" "gettimeofday" "ac_cv_func_gettimeofday"
-if test "x$ac_cv_func_gettimeofday" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_GETTIMEOFDAY 1
-_ACEOF
-
-fi
-done
-
echo "$as_me: this is boost.m4 serial 26" >&5
@@ -17525,6 +17539,1103 @@ $as_echo "$boost_cv_lib_version" >&6; }
fi
CPPFLAGS=$boost_save_CPPFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the toolset name used by Boost for $CXX" >&5
+$as_echo_n "checking for the toolset name used by Boost for $CXX... " >&6; }
+if ${boost_cv_lib_tag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_lib_tag=unknown
+if test x$boost_cv_inc_path != xno; then
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+ # The following tests are mostly inspired by boost/config/auto_link.hpp
+ # The list is sorted to most recent/common to oldest compiler (in order
+ # to increase the likelihood of finding the right compiler with the
+ # least number of compilation attempt).
+ # Beware that some tests are sensible to the order (for instance, we must
+ # look for MinGW before looking for GCC3).
+ # I used one compilation test per compiler with a #error to recognize
+ # each compiler so that it works even when cross-compiling (let me know
+ # if you know a better approach).
+ # Known missing tags (known from Boost's tools/build/v2/tools/common.jam):
+ # como, edg, kcc, bck, mp, sw, tru, xlc
+ # I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
+ # the same defines as GCC's).
+ for i in \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw63" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc63" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw62" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc62" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw61" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc61" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw60" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc60" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw54" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc54" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw53" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc53" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw52" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc52" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw51" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc51" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw50" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc50" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw410" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC @ gcc410" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw49" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC @ gcc49" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw48" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC @ gcc48" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw47" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC @ gcc47" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw46" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC @ gcc46" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw45" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC @ gcc45" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw44" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc44" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw43" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc43" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw42" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc42" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw41" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc41" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw40" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc40" \
+ "defined __GNUC__ && __GNUC__ == 3 && !defined __ICC \
+ && (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc34" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc33" \
+ "defined _MSC_VER && _MSC_VER >= 1500 @ vc90" \
+ "defined _MSC_VER && _MSC_VER == 1400 @ vc80" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc32" \
+ "defined _MSC_VER && _MSC_VER == 1310 @ vc71" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc31" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc30" \
+ "defined __BORLANDC__ @ bcb" \
+ "defined __ICC && (defined __unix || defined ) @ il" \
+ "defined __ICL @ iw" \
+ "defined _MSC_VER && _MSC_VER == 1300 @ vc7" \
+ "defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ == 95 && !defined __ICC @ gcc295" \
+ "defined __MWERKS__ && __MWERKS__ <= 0x32FF @ cw9" \
+ "defined _MSC_VER && _MSC_VER < 1300 && !defined UNDER_CE @ vc6" \
+ "defined _MSC_VER && _MSC_VER < 1300 && defined UNDER_CE @ evc4" \
+ "defined __MWERKS__ && __MWERKS__ <= 0x31FF @ cw8"
+ do
+ boost_tag_test=`expr "X$i" : 'X\([^@]*\) @ '`
+ boost_tag=`expr "X$i" : 'X[^@]* @ \(.*\)'`
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if $boost_tag_test
+/* OK */
+#else
+# error $boost_tag_test
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ boost_cv_lib_tag=$boost_tag; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ case $boost_cv_lib_tag in #(
+ # Some newer (>= 1.35?) versions of Boost seem to only use "gcc" as opposed
+ # to "gcc41" for instance.
+ *-gcc | *'-gcc ') :;; #( Don't re-add -gcc: it's already in there.
+ gcc*)
+ boost_tag_x=
+ case $host_os in #(
+ darwin*)
+ if test $boost_major_version -ge 136; then
+ # The `x' added in r46793 of Boost.
+ boost_tag_x=x
+ fi;;
+ esac
+ # We can specify multiple tags in this variable because it's used by
+ # BOOST_FIND_LIB that does a `for tag in -$boost_cv_lib_tag' ...
+ boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc"
+ ;; #(
+ unknown)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not figure out which toolset name to use for $CXX" >&5
+$as_echo "$as_me: WARNING: could not figure out which toolset name to use for $CXX" >&2;}
+ boost_cv_lib_tag=
+ ;;
+ esac
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_tag" >&5
+$as_echo "$boost_cv_lib_tag" >&6; }
+# Check whether --enable-static-boost was given.
+if test "${enable_static_boost+set}" = set; then :
+ enableval=$enable_static_boost; enable_static_boost=yes
+else
+ enable_static_boost=no
+fi
+
+# Check whether we do better use `mt' even though we weren't ask to.
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if defined _REENTRANT || defined _MT || defined __MT__
+/* use -mt */
+#else
+# error MT not needed
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ boost_guess_use_mt=:
+else
+ boost_guess_use_mt=false
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+# Do we have to check for Boost.System? This link-time dependency was
+# added as of 1.35.0. If we have a version <1.35, we must not attempt to
+# find Boost.System as it didn't exist by then.
+if test $boost_major_version -ge 135; then
+ if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost system library" >&5
+$as_echo "$as_me: Boost not available, not searching for the Boost system library" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/system/error_code.hpp" >&5
+$as_echo "$as_me: Boost not available, not searching for boost/system/error_code.hpp" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+ac_fn_cxx_check_header_mongrel "$LINENO" "boost/system/error_code.hpp" "ac_cv_header_boost_system_error_code_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_boost_system_error_code_hpp" = xyes; then :
+
+$as_echo "#define HAVE_BOOST_SYSTEM_ERROR_CODE_HPP 1" >>confdefs.h
+
+else
+ as_fn_error $? "cannot find boost/system/error_code.hpp" "$LINENO" 5
+fi
+
+
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost system library" >&5
+$as_echo_n "checking for the Boost system library... " >&6; }
+if ${boost_cv_lib_system+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_lib_system=no
+ case "" in #(
+ (mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
+ (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #(
+ (*) boost_mt=; boost_rtopt=;;
+ esac
+ if test $enable_static_boost = yes; then
+ boost_rtopt="s$boost_rtopt"
+ fi
+ # Find the proper debug variant depending on what we've been asked to find.
+ case $boost_rtopt in #(
+ (*d*) boost_rt_d=$boost_rtopt;; #(
+ (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn')
+ boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #(
+ (*) boost_rt_d='-d';;
+ esac
+ # If the PREFERRED-RT-OPT are not empty, prepend a `-'.
+ test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt"
+ $boost_guess_use_mt && boost_mt=-mt
+ # Look for the abs path the static archive.
+ # $libext is computed by Libtool but let's make sure it's non empty.
+ test -z "$libext" &&
+ as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5
+ boost_save_ac_objext=$ac_objext
+ # Generate the test file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <boost/system/error_code.hpp>
+
+int
+main ()
+{
+boost::system::error_code e; e.clear();
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_objext=do_not_rm_me_plz
+else
+ as_fn_error $? "cannot compile a test that uses Boost system" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext
+ ac_objext=$boost_save_ac_objext
+ boost_failed_libs=
+# Don't bother to ident the following nested for loops, only the 2
+# innermost ones matter.
+for boost_lib_ in system; do
+for boost_tag_ in -$boost_cv_lib_tag ''; do
+for boost_ver_ in -$boost_cv_lib_version ''; do
+for boost_mt_ in $boost_mt -mt ''; do
+for boost_rtopt_ in $boost_rtopt '' -d; do
+ for boost_lib in \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_ver_
+ do
+ # Avoid testing twice the same lib
+ case $boost_failed_libs in #(
+ (*@$boost_lib@*) continue;;
+ esac
+ # If with_boost is empty, we'll search in /lib first, which is not quite
+ # right so instead we'll try to a location based on where the headers are.
+ boost_tmp_lib=$with_boost
+ test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include}
+ for boost_ldpath in "$boost_tmp_lib/lib" '' \
+ /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \
+ "$with_boost" C:/Boost/lib /lib*
+ do
+ # Don't waste time with directories that don't exist.
+ if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then
+ continue
+ fi
+ boost_save_LDFLAGS=$LDFLAGS
+ # Are we looking for a static library?
+ case $boost_ldpath:$boost_rtopt_ in #(
+ (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt)
+ boost_cv_lib_system_LIBS="$boost_ldpath/lib$boost_lib.$libext"
+ test -e "$boost_cv_lib_system_LIBS" || continue;; #(
+ (*) # No: use -lboost_foo to find the shared library.
+ boost_cv_lib_system_LIBS="-l$boost_lib";;
+ esac
+ boost_save_LIBS=$LIBS
+ LIBS="$boost_cv_lib_system_LIBS $LIBS"
+ test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_cv_lib_system=yes
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_cv_lib_system=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ ac_objext=$boost_save_ac_objext
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ if test x"$boost_cv_lib_system" = xyes; then
+ # Check or used cached result of whether or not using -R or
+ # -rpath makes sense. Some implementations of ld, such as for
+ # Mac OSX, require -rpath but -R is the flag known to work on
+ # other systems. https://github.com/tsuna/boost.m4/issues/19
+ if ${boost_cv_rpath_link_ldflag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $boost_ldpath in
+ '') # Nothing to do.
+ boost_cv_rpath_link_ldflag=
+ boost_rpath_link_ldflag_found=yes;;
+ *)
+ for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
+ LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ LIBS="$boost_save_LIBS $boost_cv_lib_system_LIBS"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_rpath_link_ldflag_found=yes
+ break
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_rpath_link_ldflag_found=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ done
+ ;;
+ esac
+ if test "x$boost_rpath_link_ldflag_found" != "xyes"; then :
+ as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5
+fi
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+
+fi
+
+ test x"$boost_ldpath" != x &&
+ boost_cv_lib_system_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ boost_cv_lib_system_LDPATH="$boost_ldpath"
+ break 7
+ else
+ boost_failed_libs="$boost_failed_libs@$boost_lib@"
+ fi
+ done
+ done
+done
+done
+done
+done
+done # boost_lib_
+rm -f conftest.$ac_objext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_system" >&5
+$as_echo "$boost_cv_lib_system" >&6; }
+case $boost_cv_lib_system in #(
+ (no) $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ as_fn_error $? "cannot find the flags to link with Boost system" "$LINENO" 5
+ ;;
+esac
+BOOST_SYSTEM_LDFLAGS=$boost_cv_lib_system_LDFLAGS
+BOOST_SYSTEM_LDPATH=$boost_cv_lib_system_LDPATH
+BOOST_LDPATH=$boost_cv_lib_system_LDPATH
+BOOST_SYSTEM_LIBS=$boost_cv_lib_system_LIBS
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+fi
+
+
+
+fi # end of the Boost.System check.
+boost_filesystem_save_LIBS=$LIBS
+boost_filesystem_save_LDFLAGS=$LDFLAGS
+LIBS="$LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost filesystem library" >&5
+$as_echo "$as_me: Boost not available, not searching for the Boost filesystem library" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/filesystem/path.hpp" >&5
+$as_echo "$as_me: Boost not available, not searching for boost/filesystem/path.hpp" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+ac_fn_cxx_check_header_mongrel "$LINENO" "boost/filesystem/path.hpp" "ac_cv_header_boost_filesystem_path_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_boost_filesystem_path_hpp" = xyes; then :
+
+$as_echo "#define HAVE_BOOST_FILESYSTEM_PATH_HPP 1" >>confdefs.h
+
+else
+ as_fn_error $? "cannot find boost/filesystem/path.hpp" "$LINENO" 5
+fi
+
+
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost filesystem library" >&5
+$as_echo_n "checking for the Boost filesystem library... " >&6; }
+if ${boost_cv_lib_filesystem+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_lib_filesystem=no
+ case "" in #(
+ (mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
+ (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #(
+ (*) boost_mt=; boost_rtopt=;;
+ esac
+ if test $enable_static_boost = yes; then
+ boost_rtopt="s$boost_rtopt"
+ fi
+ # Find the proper debug variant depending on what we've been asked to find.
+ case $boost_rtopt in #(
+ (*d*) boost_rt_d=$boost_rtopt;; #(
+ (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn')
+ boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #(
+ (*) boost_rt_d='-d';;
+ esac
+ # If the PREFERRED-RT-OPT are not empty, prepend a `-'.
+ test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt"
+ $boost_guess_use_mt && boost_mt=-mt
+ # Look for the abs path the static archive.
+ # $libext is computed by Libtool but let's make sure it's non empty.
+ test -z "$libext" &&
+ as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5
+ boost_save_ac_objext=$ac_objext
+ # Generate the test file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <boost/filesystem/path.hpp>
+
+int
+main ()
+{
+boost::filesystem::path p;
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_objext=do_not_rm_me_plz
+else
+ as_fn_error $? "cannot compile a test that uses Boost filesystem" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext
+ ac_objext=$boost_save_ac_objext
+ boost_failed_libs=
+# Don't bother to ident the following nested for loops, only the 2
+# innermost ones matter.
+for boost_lib_ in filesystem; do
+for boost_tag_ in -$boost_cv_lib_tag ''; do
+for boost_ver_ in -$boost_cv_lib_version ''; do
+for boost_mt_ in $boost_mt -mt ''; do
+for boost_rtopt_ in $boost_rtopt '' -d; do
+ for boost_lib in \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_ver_
+ do
+ # Avoid testing twice the same lib
+ case $boost_failed_libs in #(
+ (*@$boost_lib@*) continue;;
+ esac
+ # If with_boost is empty, we'll search in /lib first, which is not quite
+ # right so instead we'll try to a location based on where the headers are.
+ boost_tmp_lib=$with_boost
+ test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include}
+ for boost_ldpath in "$boost_tmp_lib/lib" '' \
+ /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \
+ "$with_boost" C:/Boost/lib /lib*
+ do
+ # Don't waste time with directories that don't exist.
+ if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then
+ continue
+ fi
+ boost_save_LDFLAGS=$LDFLAGS
+ # Are we looking for a static library?
+ case $boost_ldpath:$boost_rtopt_ in #(
+ (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt)
+ boost_cv_lib_filesystem_LIBS="$boost_ldpath/lib$boost_lib.$libext"
+ test -e "$boost_cv_lib_filesystem_LIBS" || continue;; #(
+ (*) # No: use -lboost_foo to find the shared library.
+ boost_cv_lib_filesystem_LIBS="-l$boost_lib";;
+ esac
+ boost_save_LIBS=$LIBS
+ LIBS="$boost_cv_lib_filesystem_LIBS $LIBS"
+ test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_cv_lib_filesystem=yes
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_cv_lib_filesystem=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ ac_objext=$boost_save_ac_objext
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ if test x"$boost_cv_lib_filesystem" = xyes; then
+ # Check or used cached result of whether or not using -R or
+ # -rpath makes sense. Some implementations of ld, such as for
+ # Mac OSX, require -rpath but -R is the flag known to work on
+ # other systems. https://github.com/tsuna/boost.m4/issues/19
+ if ${boost_cv_rpath_link_ldflag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $boost_ldpath in
+ '') # Nothing to do.
+ boost_cv_rpath_link_ldflag=
+ boost_rpath_link_ldflag_found=yes;;
+ *)
+ for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
+ LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ LIBS="$boost_save_LIBS $boost_cv_lib_filesystem_LIBS"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_rpath_link_ldflag_found=yes
+ break
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_rpath_link_ldflag_found=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ done
+ ;;
+ esac
+ if test "x$boost_rpath_link_ldflag_found" != "xyes"; then :
+ as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5
+fi
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+
+fi
+
+ test x"$boost_ldpath" != x &&
+ boost_cv_lib_filesystem_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ boost_cv_lib_filesystem_LDPATH="$boost_ldpath"
+ break 7
+ else
+ boost_failed_libs="$boost_failed_libs@$boost_lib@"
+ fi
+ done
+ done
+done
+done
+done
+done
+done # boost_lib_
+rm -f conftest.$ac_objext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_filesystem" >&5
+$as_echo "$boost_cv_lib_filesystem" >&6; }
+case $boost_cv_lib_filesystem in #(
+ (no) $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ as_fn_error $? "cannot find the flags to link with Boost filesystem" "$LINENO" 5
+ ;;
+esac
+BOOST_FILESYSTEM_LDFLAGS=$boost_cv_lib_filesystem_LDFLAGS
+BOOST_FILESYSTEM_LDPATH=$boost_cv_lib_filesystem_LDPATH
+BOOST_LDPATH=$boost_cv_lib_filesystem_LDPATH
+BOOST_FILESYSTEM_LIBS=$boost_cv_lib_filesystem_LIBS
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+fi
+
+if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
+ BOOST_FILESYSTEM_LIBS="$BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
+fi
+LIBS=$boost_filesystem_save_LIBS
+LDFLAGS=$boost_filesystem_save_LDFLAGS
+
+
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost system library" >&5
+$as_echo "$as_me: Boost not available, not searching for the Boost system library" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/system/error_code.hpp" >&5
+$as_echo "$as_me: Boost not available, not searching for boost/system/error_code.hpp" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+ac_fn_cxx_check_header_mongrel "$LINENO" "boost/system/error_code.hpp" "ac_cv_header_boost_system_error_code_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_boost_system_error_code_hpp" = xyes; then :
+
+$as_echo "#define HAVE_BOOST_SYSTEM_ERROR_CODE_HPP 1" >>confdefs.h
+
+else
+ as_fn_error $? "cannot find boost/system/error_code.hpp" "$LINENO" 5
+fi
+
+
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost system library" >&5
+$as_echo_n "checking for the Boost system library... " >&6; }
+if ${boost_cv_lib_system+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_lib_system=no
+ case "" in #(
+ (mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
+ (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X" : 'Xmt-*\(.*\)'`;; #(
+ (*) boost_mt=; boost_rtopt=;;
+ esac
+ if test $enable_static_boost = yes; then
+ boost_rtopt="s$boost_rtopt"
+ fi
+ # Find the proper debug variant depending on what we've been asked to find.
+ case $boost_rtopt in #(
+ (*d*) boost_rt_d=$boost_rtopt;; #(
+ (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn')
+ boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #(
+ (*) boost_rt_d='-d';;
+ esac
+ # If the PREFERRED-RT-OPT are not empty, prepend a `-'.
+ test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt"
+ $boost_guess_use_mt && boost_mt=-mt
+ # Look for the abs path the static archive.
+ # $libext is computed by Libtool but let's make sure it's non empty.
+ test -z "$libext" &&
+ as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5
+ boost_save_ac_objext=$ac_objext
+ # Generate the test file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <boost/system/error_code.hpp>
+
+int
+main ()
+{
+boost::system::error_code e; e.clear();
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_objext=do_not_rm_me_plz
+else
+ as_fn_error $? "cannot compile a test that uses Boost system" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext
+ ac_objext=$boost_save_ac_objext
+ boost_failed_libs=
+# Don't bother to ident the following nested for loops, only the 2
+# innermost ones matter.
+for boost_lib_ in system; do
+for boost_tag_ in -$boost_cv_lib_tag ''; do
+for boost_ver_ in -$boost_cv_lib_version ''; do
+for boost_mt_ in $boost_mt -mt ''; do
+for boost_rtopt_ in $boost_rtopt '' -d; do
+ for boost_lib in \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_ver_
+ do
+ # Avoid testing twice the same lib
+ case $boost_failed_libs in #(
+ (*@$boost_lib@*) continue;;
+ esac
+ # If with_boost is empty, we'll search in /lib first, which is not quite
+ # right so instead we'll try to a location based on where the headers are.
+ boost_tmp_lib=$with_boost
+ test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include}
+ for boost_ldpath in "$boost_tmp_lib/lib" '' \
+ /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \
+ "$with_boost" C:/Boost/lib /lib*
+ do
+ # Don't waste time with directories that don't exist.
+ if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then
+ continue
+ fi
+ boost_save_LDFLAGS=$LDFLAGS
+ # Are we looking for a static library?
+ case $boost_ldpath:$boost_rtopt_ in #(
+ (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt)
+ boost_cv_lib_system_LIBS="$boost_ldpath/lib$boost_lib.$libext"
+ test -e "$boost_cv_lib_system_LIBS" || continue;; #(
+ (*) # No: use -lboost_foo to find the shared library.
+ boost_cv_lib_system_LIBS="-l$boost_lib";;
+ esac
+ boost_save_LIBS=$LIBS
+ LIBS="$boost_cv_lib_system_LIBS $LIBS"
+ test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_cv_lib_system=yes
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_cv_lib_system=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ ac_objext=$boost_save_ac_objext
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ if test x"$boost_cv_lib_system" = xyes; then
+ # Check or used cached result of whether or not using -R or
+ # -rpath makes sense. Some implementations of ld, such as for
+ # Mac OSX, require -rpath but -R is the flag known to work on
+ # other systems. https://github.com/tsuna/boost.m4/issues/19
+ if ${boost_cv_rpath_link_ldflag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $boost_ldpath in
+ '') # Nothing to do.
+ boost_cv_rpath_link_ldflag=
+ boost_rpath_link_ldflag_found=yes;;
+ *)
+ for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
+ LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ LIBS="$boost_save_LIBS $boost_cv_lib_system_LIBS"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_rpath_link_ldflag_found=yes
+ break
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_rpath_link_ldflag_found=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ done
+ ;;
+ esac
+ if test "x$boost_rpath_link_ldflag_found" != "xyes"; then :
+ as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5
+fi
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+
+fi
+
+ test x"$boost_ldpath" != x &&
+ boost_cv_lib_system_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ boost_cv_lib_system_LDPATH="$boost_ldpath"
+ break 7
+ else
+ boost_failed_libs="$boost_failed_libs@$boost_lib@"
+ fi
+ done
+ done
+done
+done
+done
+done
+done # boost_lib_
+rm -f conftest.$ac_objext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_system" >&5
+$as_echo "$boost_cv_lib_system" >&6; }
+case $boost_cv_lib_system in #(
+ (no) $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ as_fn_error $? "cannot find the flags to link with Boost system" "$LINENO" 5
+ ;;
+esac
+BOOST_SYSTEM_LDFLAGS=$boost_cv_lib_system_LDFLAGS
+BOOST_SYSTEM_LDPATH=$boost_cv_lib_system_LDPATH
+BOOST_LDPATH=$boost_cv_lib_system_LDPATH
+BOOST_SYSTEM_LIBS=$boost_cv_lib_system_LIBS
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+fi
+
+
+
# =====
# Debug
@@ -17680,12 +18791,12 @@ if test -n "$MDDS_CFLAGS"; then
pkg_cv_MDDS_CFLAGS="$MDDS_CFLAGS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mdds-1.2 >= 1.2.0\""; } >&5
- ($PKG_CONFIG --exists --print-errors "mdds-1.2 >= 1.2.0") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mdds-1.4 >= 1.4.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "mdds-1.4 >= 1.4.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_MDDS_CFLAGS=`$PKG_CONFIG --cflags "mdds-1.2 >= 1.2.0" 2>/dev/null`
+ pkg_cv_MDDS_CFLAGS=`$PKG_CONFIG --cflags "mdds-1.4 >= 1.4.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -17697,12 +18808,12 @@ if test -n "$MDDS_LIBS"; then
pkg_cv_MDDS_LIBS="$MDDS_LIBS"
elif test -n "$PKG_CONFIG"; then
if test -n "$PKG_CONFIG" && \
- { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mdds-1.2 >= 1.2.0\""; } >&5
- ($PKG_CONFIG --exists --print-errors "mdds-1.2 >= 1.2.0") 2>&5
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"mdds-1.4 >= 1.4.0\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "mdds-1.4 >= 1.4.0") 2>&5
ac_status=$?
$as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; then
- pkg_cv_MDDS_LIBS=`$PKG_CONFIG --libs "mdds-1.2 >= 1.2.0" 2>/dev/null`
+ pkg_cv_MDDS_LIBS=`$PKG_CONFIG --libs "mdds-1.4 >= 1.4.0" 2>/dev/null`
test "x$?" != "x0" && pkg_failed=yes
else
pkg_failed=yes
@@ -17723,14 +18834,14 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- MDDS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "mdds-1.2 >= 1.2.0" 2>&1`
+ MDDS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "mdds-1.4 >= 1.4.0" 2>&1`
else
- MDDS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "mdds-1.2 >= 1.2.0" 2>&1`
+ MDDS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "mdds-1.4 >= 1.4.0" 2>&1`
fi
# Put the nasty error message in config.log where it belongs
echo "$MDDS_PKG_ERRORS" >&5
- as_fn_error $? "Package requirements (mdds-1.2 >= 1.2.0) were not met:
+ as_fn_error $? "Package requirements (mdds-1.4 >= 1.4.0) were not met:
$MDDS_PKG_ERRORS
@@ -17807,7 +18918,7 @@ if ${am_cv_pathless_PYTHON+:} false; then :
$as_echo_n "(cached) " >&6
else
- for am_cv_pathless_PYTHON in python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
+ for am_cv_pathless_PYTHON in python python2 python3 python3.8 python3.7 python3.6 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do
test "$am_cv_pathless_PYTHON" = none && break
prog="import sys
# split strings by '.' and convert to numeric. Append some zeros
@@ -18147,6 +19258,14 @@ else
IXION_THREADS_FALSE=
fi
+ if test "x$enable_cuda" != "xno"; then
+ BUILD_CUDA_TRUE=
+ BUILD_CUDA_FALSE='#'
+else
+ BUILD_CUDA_TRUE='#'
+ BUILD_CUDA_FALSE=
+fi
+
if test "x$_os" = "xDarwin"; then
OSX_TRUE=
OSX_FALSE='#'
@@ -18156,231 +19275,6 @@ else
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the toolset name used by Boost for $CXX" >&5
-$as_echo_n "checking for the toolset name used by Boost for $CXX... " >&6; }
-if ${boost_cv_lib_tag+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- boost_cv_lib_tag=unknown
-if test x$boost_cv_inc_path != xno; then
- ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
- # The following tests are mostly inspired by boost/config/auto_link.hpp
- # The list is sorted to most recent/common to oldest compiler (in order
- # to increase the likelihood of finding the right compiler with the
- # least number of compilation attempt).
- # Beware that some tests are sensible to the order (for instance, we must
- # look for MinGW before looking for GCC3).
- # I used one compilation test per compiler with a #error to recognize
- # each compiler so that it works even when cross-compiling (let me know
- # if you know a better approach).
- # Known missing tags (known from Boost's tools/build/v2/tools/common.jam):
- # como, edg, kcc, bck, mp, sw, tru, xlc
- # I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
- # the same defines as GCC's).
- for i in \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw63" \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc63" \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw62" \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc62" \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw61" \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc61" \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw60" \
- "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc60" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw54" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc54" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw53" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc53" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw52" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc52" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw51" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc51" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw50" \
- "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc50" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw410" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC @ gcc410" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw49" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC @ gcc49" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw48" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC @ gcc48" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw47" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC @ gcc47" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw46" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC @ gcc46" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw45" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC @ gcc45" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw44" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc44" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw43" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc43" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw42" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc42" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw41" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc41" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC && \
- (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw40" \
- "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc40" \
- "defined __GNUC__ && __GNUC__ == 3 && !defined __ICC \
- && (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
- || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw" \
- "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc34" \
- "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc33" \
- "defined _MSC_VER && _MSC_VER >= 1500 @ vc90" \
- "defined _MSC_VER && _MSC_VER == 1400 @ vc80" \
- "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc32" \
- "defined _MSC_VER && _MSC_VER == 1310 @ vc71" \
- "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc31" \
- "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc30" \
- "defined __BORLANDC__ @ bcb" \
- "defined __ICC && (defined __unix || defined ) @ il" \
- "defined __ICL @ iw" \
- "defined _MSC_VER && _MSC_VER == 1300 @ vc7" \
- "defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ == 95 && !defined __ICC @ gcc295" \
- "defined __MWERKS__ && __MWERKS__ <= 0x32FF @ cw9" \
- "defined _MSC_VER && _MSC_VER < 1300 && !defined UNDER_CE @ vc6" \
- "defined _MSC_VER && _MSC_VER < 1300 && defined UNDER_CE @ evc4" \
- "defined __MWERKS__ && __MWERKS__ <= 0x31FF @ cw8"
- do
- boost_tag_test=`expr "X$i" : 'X\([^@]*\) @ '`
- boost_tag=`expr "X$i" : 'X[^@]* @ \(.*\)'`
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-#if $boost_tag_test
-/* OK */
-#else
-# error $boost_tag_test
-#endif
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
- boost_cv_lib_tag=$boost_tag; break
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- done
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
- case $boost_cv_lib_tag in #(
- # Some newer (>= 1.35?) versions of Boost seem to only use "gcc" as opposed
- # to "gcc41" for instance.
- *-gcc | *'-gcc ') :;; #( Don't re-add -gcc: it's already in there.
- gcc*)
- boost_tag_x=
- case $host_os in #(
- darwin*)
- if test $boost_major_version -ge 136; then
- # The `x' added in r46793 of Boost.
- boost_tag_x=x
- fi;;
- esac
- # We can specify multiple tags in this variable because it's used by
- # BOOST_FIND_LIB that does a `for tag in -$boost_cv_lib_tag' ...
- boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc"
- ;; #(
- unknown)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not figure out which toolset name to use for $CXX" >&5
-$as_echo "$as_me: WARNING: could not figure out which toolset name to use for $CXX" >&2;}
- boost_cv_lib_tag=
- ;;
- esac
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_tag" >&5
-$as_echo "$boost_cv_lib_tag" >&6; }
-# Check whether --enable-static-boost was given.
-if test "${enable_static_boost+set}" = set; then :
- enableval=$enable_static_boost; enable_static_boost=yes
-else
- enable_static_boost=no
-fi
-
-# Check whether we do better use `mt' even though we weren't ask to.
-ac_ext=cpp
-ac_cpp='$CXXCPP $CPPFLAGS'
-ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-#if defined _REENTRANT || defined _MT || defined __MT__
-/* use -mt */
-#else
-# error MT not needed
-#endif
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_compile "$LINENO"; then :
- boost_guess_use_mt=:
-else
- boost_guess_use_mt=false
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
if test x"$boost_cv_inc_path" = xno; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost program_options library" >&5
$as_echo "$as_me: Boost not available, not searching for the Boost program_options library" >&6;}
@@ -18819,6 +19713,10 @@ if test -z "${IXION_THREADS_TRUE}" && test -z "${IXION_THREADS_FALSE}"; then
as_fn_error $? "conditional \"IXION_THREADS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${BUILD_CUDA_TRUE}" && test -z "${BUILD_CUDA_FALSE}"; then
+ as_fn_error $? "conditional \"BUILD_CUDA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${OSX_TRUE}" && test -z "${OSX_FALSE}"; then
as_fn_error $? "conditional \"OSX\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -19220,7 +20118,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by libixion $as_me 0.13.0, which was
+This file was extended by libixion $as_me 0.14.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -19286,7 +20184,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-libixion config.status 0.13.0
+libixion config.status 0.14.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -20515,7 +21413,6 @@ $as_echo X"$file" |
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
# Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
# Provide generalized library-building support services.
@@ -21258,6 +22155,7 @@ Build configuration:
host os: $host_os
python: $enable_python
threads: $enable_threads
+ cuda: $enable_cuda
==============================================================================
" >&5
$as_echo "$as_me:
@@ -21266,5 +22164,6 @@ Build configuration:
host os: $host_os
python: $enable_python
threads: $enable_threads
+ cuda: $enable_cuda
==============================================================================
" >&6;}
diff --git a/configure.ac b/configure.ac
index 71819f1..388f85a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,11 +2,11 @@
# Process this file with autoconf to produce a configure script.
m4_define([ixion_major_version], [0])
-m4_define([ixion_minor_version], [13])
+m4_define([ixion_minor_version], [14])
m4_define([ixion_micro_version], [0])
m4_define([ixion_major_api_version], [0])
-m4_define([ixion_minor_api_version], [13])
+m4_define([ixion_minor_api_version], [14])
m4_define([ixion_version],
[ixion_major_version.ixion_minor_version.ixion_micro_version])
@@ -32,7 +32,7 @@ case $host_os in
;;
*)
_os=
- LDFLAGS="$LDFLAGS -Wl,--no-as-needed -pthread"
+ LDFLAGS="$LDFLAGS -Wl,--no-as-needed -pthread -ldl"
;;
esac
@@ -48,16 +48,26 @@ AC_ARG_ENABLE([threads],
[enable_threads=yes]
)
+AC_ARG_ENABLE([cuda],
+ [AS_HELP_STRING([--enable-cuda], [Enable CUDA compute engine])],
+ [enable_cuda="$enableval"],
+ [enable_cuda=no]
+)
+
IXION_VERSION=ixion_version
IXION_API_VERSION=ixion_api_version
IXION_MAJOR_VERSION=ixion_major_version
IXION_MINOR_VERSION=ixion_minor_version
IXION_MICRO_VERSION=ixion_micro_version
+IXION_MAJOR_API_VERSION=ixion_major_api_version
+IXION_MINOR_API_VERSION=ixion_minor_api_version
AC_SUBST(IXION_VERSION)
AC_SUBST(IXION_API_VERSION)
AC_SUBST(IXION_MAJOR_VERSION)
AC_SUBST(IXION_MINOR_VERSION)
AC_SUBST(IXION_MICRO_VERSION)
+AC_SUBST(IXION_MAJOR_API_VERSION)
+AC_SUBST(IXION_MINOR_API_VERSION)
AC_CONFIG_MACRO_DIR([m4])
@@ -86,9 +96,10 @@ AC_TYPE_SIZE_T
# Checks for library functions.
AC_FUNC_STRTOD
-AC_CHECK_FUNCS([gettimeofday])
BOOST_REQUIRE([1.36])
+BOOST_FILESYSTEM
+BOOST_SYSTEM
# =====
# Debug
@@ -106,7 +117,7 @@ AS_IF([test "x$enable_debug" != "xno"], [
])
# Check for mdds.
-PKG_CHECK_MODULES([MDDS],[mdds-1.2 >= 1.2.0])
+PKG_CHECK_MODULES([MDDS],[mdds-1.4 >= 1.4.0])
# Check for python.
AS_IF([test "x$enable_python" != "xno"], [
@@ -122,6 +133,7 @@ AS_IF([test "x$enable_threads" != "xno"], [
AM_CONDITIONAL([BUILD_PYTHON], [test "x$enable_python" != "xno"])
AM_CONDITIONAL([IXION_THREADS], [test "x$enable_threads" != "xno"])
+AM_CONDITIONAL([BUILD_CUDA], [test "x$enable_cuda" != "xno"])
AM_CONDITIONAL([OSX], [test "x$_os" = "xDarwin"])
BOOST_PROGRAM_OPTIONS
@@ -145,5 +157,6 @@ Build configuration:
host os: $host_os
python: $enable_python
threads: $enable_threads
+ cuda: $enable_cuda
==============================================================================
])
diff --git a/depcomp b/depcomp
index fc98710..b39f98f 100755
--- a/depcomp
+++ b/depcomp
@@ -1,9 +1,9 @@
#! /bin/sh
# depcomp - compile a program generating dependencies as side-effects
-scriptversion=2013-05-30.07; # UTC
+scriptversion=2016-01-11.22; # UTC
-# Copyright (C) 1999-2014 Free Software Foundation, Inc.
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -786,6 +786,6 @@ exit 0
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
+# time-stamp-time-zone: "UTC0"
# time-stamp-end: "; # UTC"
# End:
diff --git a/include/Makefile.in b/include/Makefile.in
index 8ec5889..d7b1bc5 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -193,11 +193,17 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
BOOST_LDPATH = @BOOST_LDPATH@
BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
@@ -228,8 +234,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IXION_API_VERSION = @IXION_API_VERSION@
+IXION_MAJOR_API_VERSION = @IXION_MAJOR_API_VERSION@
IXION_MAJOR_VERSION = @IXION_MAJOR_VERSION@
IXION_MICRO_VERSION = @IXION_MICRO_VERSION@
+IXION_MINOR_API_VERSION = @IXION_MINOR_API_VERSION@
IXION_MINOR_VERSION = @IXION_MINOR_VERSION@
IXION_VERSION = @IXION_VERSION@
LD = @LD@
diff --git a/include/ixion/Makefile.am b/include/ixion/Makefile.am
index 14b1801..72799eb 100644
--- a/include/ixion/Makefile.am
+++ b/include/ixion/Makefile.am
@@ -3,9 +3,11 @@ SUBDIRS = interface
libixiondir = $(includedir)/libixion-@IXION_API_VERSION@/ixion
libixion_HEADERS = \
address.hpp \
+ address_iterator.hpp \
cell.hpp \
cell_listener_tracker.hpp \
column_store_type.hpp \
+ compute_engine.hpp \
config.hpp \
depth_first_search.hpp \
env.hpp \
@@ -16,11 +18,13 @@ libixion_HEADERS = \
formula_opcode.hpp \
formula_result.hpp \
formula_tokens.hpp \
+ formula_tokens_fwd.hpp \
global.hpp \
info.hpp \
macros.hpp \
matrix.hpp \
mem_str_buf.hpp \
model_context.hpp \
+ module.hpp \
table.hpp \
types.hpp
diff --git a/include/ixion/Makefile.in b/include/ixion/Makefile.in
index 1eca662..fa9dad8 100644
--- a/include/ixion/Makefile.in
+++ b/include/ixion/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -224,11 +224,17 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
BOOST_LDPATH = @BOOST_LDPATH@
BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
@@ -259,8 +265,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IXION_API_VERSION = @IXION_API_VERSION@
+IXION_MAJOR_API_VERSION = @IXION_MAJOR_API_VERSION@
IXION_MAJOR_VERSION = @IXION_MAJOR_VERSION@
IXION_MICRO_VERSION = @IXION_MICRO_VERSION@
+IXION_MINOR_API_VERSION = @IXION_MINOR_API_VERSION@
IXION_MINOR_VERSION = @IXION_MINOR_VERSION@
IXION_VERSION = @IXION_VERSION@
LD = @LD@
@@ -370,9 +378,11 @@ SUBDIRS = interface
libixiondir = $(includedir)/libixion-@IXION_API_VERSION@/ixion
libixion_HEADERS = \
address.hpp \
+ address_iterator.hpp \
cell.hpp \
cell_listener_tracker.hpp \
column_store_type.hpp \
+ compute_engine.hpp \
config.hpp \
depth_first_search.hpp \
env.hpp \
@@ -383,12 +393,14 @@ libixion_HEADERS = \
formula_opcode.hpp \
formula_result.hpp \
formula_tokens.hpp \
+ formula_tokens_fwd.hpp \
global.hpp \
info.hpp \
macros.hpp \
matrix.hpp \
mem_str_buf.hpp \
model_context.hpp \
+ module.hpp \
table.hpp \
types.hpp
diff --git a/include/ixion/address.hpp b/include/ixion/address.hpp
index a1d34ae..3442a52 100644
--- a/include/ixion/address.hpp
+++ b/include/ixion/address.hpp
@@ -5,8 +5,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
-#ifndef __IXION_ADDRESS_HPP__
-#define __IXION_ADDRESS_HPP__
+#ifndef INCLUDED_IXION_ADDRESS_HPP
+#define INCLUDED_IXION_ADDRESS_HPP
#include "ixion/global.hpp"
@@ -104,6 +104,51 @@ IXION_DLLPUBLIC bool operator==(const address_t& left, const address_t& right);
IXION_DLLPUBLIC bool operator!=(const address_t& left, const address_t& right);
IXION_DLLPUBLIC bool operator<(const address_t& left, const address_t& right);
+struct IXION_DLLPUBLIC abs_rc_address_t
+{
+ enum init_invalid { invalid };
+
+ row_t row;
+ col_t column;
+
+ abs_rc_address_t();
+ abs_rc_address_t(init_invalid);
+ abs_rc_address_t(row_t row, col_t column);
+ abs_rc_address_t(const abs_rc_address_t& r);
+
+ bool valid() const;
+
+ struct hash
+ {
+ IXION_DLLPUBLIC size_t operator() (const abs_rc_address_t& addr) const;
+ };
+};
+
+IXION_DLLPUBLIC bool operator==(const abs_rc_address_t& left, const abs_rc_address_t& right);
+IXION_DLLPUBLIC bool operator!=(const abs_rc_address_t& left, const abs_rc_address_t& right);
+IXION_DLLPUBLIC bool operator<(const abs_rc_address_t& left, const abs_rc_address_t& right);
+
+/**
+ * Stores either absolute or relative address, but unlike the {@link
+ * address_t} counterpart, this struct only stores row and column positions.
+ */
+struct IXION_DLLPUBLIC rc_address_t
+{
+ row_t row;
+ col_t column;
+ bool abs_row:1;
+ bool abs_column:1;
+
+ rc_address_t();
+ rc_address_t(row_t row, col_t column, bool abs_row=true, bool abs_column=true);
+ rc_address_t(const rc_address_t& r);
+
+ struct hash
+ {
+ IXION_DLLPUBLIC size_t operator() (const rc_address_t& addr) const;
+ };
+};
+
/**
* Stores absolute range address.
*/
@@ -125,28 +170,28 @@ struct IXION_DLLPUBLIC abs_range_t
bool valid() const;
/**
- * Expand the range to include the entire columns. The row range will
- * remain unchanged.
+ * Expand the range horizontally to include all columns. The row range
+ * will remain unchanged.
*/
- void set_whole_column();
+ void set_all_columns();
/**
- * Expand the range to include the entire rows. The column range will
+ * Expand the range vertically to include all rows. The column range will
* remain unchanged.
*/
- void set_whole_row();
+ void set_all_rows();
/**
- * @return true if the range is unspecified in the column direction,
- * false otherwise.
+ * @return true if the range is unspecified in the horizontal direction
+ * i.e. all columns are selected, false otherwise.
*/
- bool whole_column() const;
+ bool all_columns() const;
/**
- * @return true if the range is unspecified in the row direction, false
- * otherwise.
+ * @return true if the range is unspecified in the vertical direction i.e.
+ * all rows are selected, false otherwise.
*/
- bool whole_row() const;
+ bool all_rows() const;
/**
* Check whether or not a given address is contained within this range.
@@ -158,6 +203,57 @@ IXION_DLLPUBLIC bool operator==(const abs_range_t& left, const abs_range_t& righ
IXION_DLLPUBLIC bool operator!=(const abs_range_t& left, const abs_range_t& right);
IXION_DLLPUBLIC bool operator<(const abs_range_t& left, const abs_range_t& right);
+struct IXION_DLLPUBLIC abs_rc_range_t
+{
+ enum init_invalid { invalid };
+
+ abs_rc_address_t first;
+ abs_rc_address_t last;
+
+ abs_rc_range_t();
+ abs_rc_range_t(init_invalid);
+
+ struct hash
+ {
+ IXION_DLLPUBLIC size_t operator() (const abs_rc_range_t& range) const;
+ };
+
+ bool valid() const;
+
+ /**
+ * Expand the range horizontally to include all columns. The row range
+ * will remain unchanged.
+ */
+ void set_all_columns();
+
+ /**
+ * Expand the range vertically to include all rows. The column range will
+ * remain unchanged.
+ */
+ void set_all_rows();
+
+ /**
+ * @return true if the range is unspecified in the horizontal direction
+ * i.e. all columns are selected, false otherwise.
+ */
+ bool all_columns() const;
+
+ /**
+ * @return true if the range is unspecified in the vertical direction i.e.
+ * all rows are selected, false otherwise.
+ */
+ bool all_rows() const;
+
+ /**
+ * Check whether or not a given address is contained within this range.
+ */
+ bool contains(const abs_rc_address_t& addr) const;
+};
+
+IXION_DLLPUBLIC bool operator==(const abs_rc_range_t& left, const abs_rc_range_t& right);
+IXION_DLLPUBLIC bool operator!=(const abs_rc_range_t& left, const abs_rc_range_t& right);
+IXION_DLLPUBLIC bool operator<(const abs_rc_range_t& left, const abs_rc_range_t& right);
+
/**
* Stores range whose component may be relative or absolute.
*/
@@ -174,28 +270,28 @@ struct IXION_DLLPUBLIC range_t
bool valid() const;
/**
- * Expand the range to include the entire columns. The row range will
- * remain unchanged.
+ * Expand the range horizontally to include all columns. The row range
+ * will remain unchanged.
*/
- void set_whole_column();
+ void set_all_columns();
/**
- * Expand the range to include the entire rows. The column range will
+ * Expand the range vertically to include all rows. The column range will
* remain unchanged.
*/
- void set_whole_row();
+ void set_all_rows();
/**
- * @return true if the range is unspecified in the column direction,
- * false otherwise.
+ * @return true if the range is unspecified in the horizontal direction
+ * i.e. all columns are selected, false otherwise.
*/
- bool whole_column() const;
+ bool all_columns() const;
/**
- * @return true if the range is unspecified in the row direction, false
- * otherwise.
+ * @return true if the range is unspecified in the vertical direction i.e.
+ * all rows are selected, false otherwise.
*/
- bool whole_row() const;
+ bool all_rows() const;
abs_range_t to_abs(const abs_address_t& origin) const;
diff --git a/include/ixion/address_iterator.hpp b/include/ixion/address_iterator.hpp
new file mode 100644
index 0000000..1aac330
--- /dev/null
+++ b/include/ixion/address_iterator.hpp
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_ADDRESS_ITERATOR_HPP
+#define INCLUDED_IXION_ADDRESS_ITERATOR_HPP
+
+#include "ixion/env.hpp"
+
+#include <memory>
+
+namespace ixion {
+
+struct abs_range_t;
+struct abs_address_t;
+
+class IXION_DLLPUBLIC abs_address_iterator
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ enum class direction_type { horizontal, vertical };
+
+ class IXION_DLLPUBLIC const_iterator
+ {
+ friend class abs_address_iterator;
+
+ struct impl_node;
+ std::unique_ptr<impl_node> mp_impl;
+
+ const_iterator(const abs_range_t& range, direction_type dir, bool end);
+ public:
+ using value_type = abs_address_t;
+
+ const_iterator();
+ const_iterator(const const_iterator& r);
+ const_iterator(const_iterator&& r);
+ ~const_iterator();
+
+ const_iterator& operator++();
+ const_iterator operator++(int);
+ const_iterator& operator--();
+ const_iterator operator--(int);
+
+ const value_type& operator*() const;
+ const value_type* operator->() const;
+
+ bool operator== (const const_iterator& r) const;
+ bool operator!= (const const_iterator& r) const;
+ };
+
+ abs_address_iterator(const abs_range_t& range, direction_type dir);
+ ~abs_address_iterator();
+
+ const_iterator begin() const;
+ const_iterator end() const;
+ const_iterator cbegin() const;
+ const_iterator cend() const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/cell.hpp b/include/ixion/cell.hpp
index 0cd6969..750fb7b 100644
--- a/include/ixion/cell.hpp
+++ b/include/ixion/cell.hpp
@@ -9,6 +9,7 @@
#define INCLUDED_IXION_CELL_HPP
#include "ixion/types.hpp"
+#include "ixion/formula_tokens_fwd.hpp"
#include <memory>
#include <vector>
@@ -17,8 +18,12 @@ namespace ixion {
class formula_result;
class formula_cell;
-class formula_token;
struct abs_address_t;
+struct rc_address_t;
+
+// calc_status is internal.
+struct calc_status;
+using calc_status_ptr_t = boost::intrusive_ptr<calc_status>;
namespace iface {
@@ -36,11 +41,17 @@ public:
formula_cell& operator= (formula_cell) = delete;
formula_cell();
- formula_cell(size_t tokens_identifier);
+ formula_cell(const formula_tokens_store_ptr_t& tokens);
+
+ formula_cell(
+ row_t group_row, col_t group_col,
+ const calc_status_ptr_t& cs,
+ const formula_tokens_store_ptr_t& tokens);
+
~formula_cell();
- size_t get_identifier() const;
- void set_identifier(size_t identifier);
+ const formula_tokens_store_ptr_t& get_tokens() const;
+ void set_tokens(const formula_tokens_store_ptr_t& tokens);
double get_value() const;
double get_value_nowait() const;
@@ -72,11 +83,35 @@ public:
std::vector<const formula_token*> get_ref_tokens(
const iface::formula_model_access& cxt, const abs_address_t& pos) const;
- const formula_result& get_result_cache() const;
- const formula_result* get_result_cache_nowait() const;
+ const formula_result& get_raw_result_cache() const;
+ const formula_result* get_raw_result_cache_nowait() const;
+
+ /**
+ * Get the cached result as a single cell. For a non-grouped formula
+ * cell, it should be identical to the value from the {@link
+ * get_result_cache} call. For a grouped formula cell, you'll get a
+ * single value assigned to the position of the cell in case the original
+ * result is a matrix value.
+ *
+ * @return formula result.
+ */
+ formula_result get_result_cache() const;
- bool is_shared() const;
- void set_shared(bool b);
+ formula_result get_result_cache_nowait() const;
+
+ formula_group_t get_group_properties() const;
+
+ /**
+ * Get the absolute parent position of a grouped formula cell. If the
+ * cell is not grouped, it simply returns the original position passed to
+ * this method.
+ *
+ * @param pos original position from which to calculate the parent
+ * position.
+ *
+ * @return parent position of the grouped formula cell.
+ */
+ abs_address_t get_parent_position(const abs_address_t& pos) const;
};
}
diff --git a/include/ixion/cell_listener_tracker.hpp b/include/ixion/cell_listener_tracker.hpp
index 3fee397..4cc6081 100644
--- a/include/ixion/cell_listener_tracker.hpp
+++ b/include/ixion/cell_listener_tracker.hpp
@@ -17,12 +17,7 @@
namespace ixion {
class formula_name_resolver;
-
-namespace iface {
-
-class formula_model_access;
-
-}
+class model_context;
/**
* Track all single and range references being listened to by individual
@@ -39,10 +34,9 @@ public:
cell_listener_tracker(const cell_listener_tracker&) = delete;
cell_listener_tracker& operator=(const cell_listener_tracker&) = delete;
- cell_listener_tracker(iface::formula_model_access& cxt);
-
typedef std::unordered_set<abs_address_t, abs_address_t::hash> address_set_type;
+ cell_listener_tracker(model_context& cxt);
~cell_listener_tracker();
/**
@@ -89,7 +83,36 @@ public:
*/
void get_all_range_listeners(const abs_address_t& target, dirty_formula_cells_t& listeners) const;
- void print_cell_listeners(const abs_address_t& target, const formula_name_resolver& resolver) const;
+ /**
+ * Register a new grouped range. A grouped range is a range whose
+ * top-left cell is always used to track dependency. One example of a
+ * grouped range is a group of matrix formula cells.
+ *
+ * Note that grouped ranges cannot overlap with each other.
+ *
+ * @param sheet index of the sheet on which the grouped range exists.
+ * @param range grouped range to add to the collection.
+ * @param identity identity of the grouped range.
+ */
+ void add_grouped_range(sheet_t sheet, const abs_rc_range_t& range, uintptr_t identity);
+
+ /**
+ * Remove an existing grouped range from being tracked.
+ *
+ * @param sheet index of the sheet on which the grouped range to be
+ * removed currently exists.
+ * @param identity identity of the range to be removed.
+ */
+ void remove_grouped_range(sheet_t sheet, uintptr_t identity);
+
+ /**
+ * Move the cell position to the top-left corner of a grouped range if the
+ * specified position falls within a grouped range. Nothing happens if
+ * the specified position is not within any grouped range.
+ *
+ * @param pos cell position to move.
+ */
+ abs_rc_address_t move_to_grouped_range_origin(sheet_t sheet, const abs_rc_address_t& pos) const;
};
}
diff --git a/include/ixion/column_store_type.hpp b/include/ixion/column_store_type.hpp
index df89d94..60ecbf8 100644
--- a/include/ixion/column_store_type.hpp
+++ b/include/ixion/column_store_type.hpp
@@ -16,6 +16,7 @@
#include <mdds/multi_type_vector.hpp>
#include <mdds/multi_type_vector_macro.hpp>
#include <mdds/multi_type_vector_custom_func1.hpp>
+#include <mdds/multi_type_matrix.hpp>
namespace ixion {
@@ -46,6 +47,20 @@ typedef mdds::multi_type_vector<ixion_element_block_func> column_store_t;
/** Type that represents a collection of columns. */
typedef std::vector<column_store_t*> column_stores_t;
+/**
+ * The integer element blocks are used to store string ID's. The actual
+ * string element blocks are not used in the matrix store in ixion.
+ */
+struct matrix_store_trait
+{
+ typedef mdds::mtv::ulong_element_block integer_element_block;
+ typedef mdds::mtv::string_element_block string_element_block;
+
+ typedef mdds::mtv::element_block_func element_block_func;
+};
+
+typedef mdds::multi_type_matrix<matrix_store_trait> matrix_store_t;
+
}
#endif
diff --git a/include/ixion/compute_engine.hpp b/include/ixion/compute_engine.hpp
new file mode 100644
index 0000000..a7f13b3
--- /dev/null
+++ b/include/ixion/compute_engine.hpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_COMPUTE_ENGINE_HPP
+#define INCLUDED_IXION_COMPUTE_ENGINE_HPP
+
+#include "ixion/env.hpp"
+#include "ixion/module.hpp"
+#include <memory>
+
+namespace ixion { namespace draft {
+
+/**
+ * Default compute engine class that uses CPU for all its computations.
+ *
+ * <p>This class also serves as the fallback for its child classes in case
+ * they don't support the function being requested or the function doesn't
+ * meet the criteria that it requires.</p>
+ *
+ * <p>Each function of this class should not modify the state of the class
+ * instance.</p>
+ */
+class IXION_DLLPUBLIC compute_engine
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ /**
+ * Create a compute engine instance.
+ *
+ * @param name name of the compute engine, or nullptr for the default one.
+ *
+ * @return compute engine instance associted with the specified name. Note
+ * that if no compute engine is registered with the specified
+ * name, the default one is created.
+ */
+ static std::shared_ptr<compute_engine> create(const char* name = nullptr);
+
+ /**
+ * Add a new compute engine class.
+ *
+ * @param name name of the compute engine.
+ * @param func_create function that creates a new instance of this compute
+ * engine class.
+ * @param func_destroy function that destroyes the instance of this
+ * compute engine class.
+ */
+ static void add_class(
+ const char* name, create_compute_engine_t func_create, destroy_compute_engine_t func_destroy);
+
+ compute_engine();
+ virtual ~compute_engine();
+
+ virtual const char* get_name() const;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/config.hpp b/include/ixion/config.hpp
index 1171c7b..291480b 100644
--- a/include/ixion/config.hpp
+++ b/include/ixion/config.hpp
@@ -9,6 +9,7 @@
#define __IXION_CONFIG_HPP__
#include "ixion/env.hpp"
+#include <cstdint>
namespace ixion {
@@ -23,6 +24,22 @@ struct IXION_DLLPUBLIC config
*/
char sep_function_arg;
+ /**
+ * Matrix column separator.
+ */
+ char sep_matrix_column;
+
+ /**
+ * Matrix row separator.
+ */
+ char sep_matrix_row;
+
+ /**
+ * Precision to use when converting a numeric value to a string
+ * representation. A negative value indicates an unspecified precision.
+ */
+ int8_t output_precision;
+
config();
config(const config& r);
};
diff --git a/include/ixion/formula_function_opcode.hpp b/include/ixion/formula_function_opcode.hpp
index 171c225..9a0e74d 100644
--- a/include/ixion/formula_function_opcode.hpp
+++ b/include/ixion/formula_function_opcode.hpp
@@ -33,6 +33,9 @@ enum class formula_function_t
// date & time functions
func_now,
+ // array functions
+ func_mmult,
+
// other
func_subtotal,
diff --git a/include/ixion/formula_result.hpp b/include/ixion/formula_result.hpp
index 0ccf5d8..4f7ca27 100644
--- a/include/ixion/formula_result.hpp
+++ b/include/ixion/formula_result.hpp
@@ -15,6 +15,8 @@
namespace ixion {
+class matrix;
+
namespace iface {
class formula_model_access;
@@ -31,10 +33,11 @@ class IXION_DLLPUBLIC formula_result
std::unique_ptr<impl> mp_impl;
public:
- enum class result_type { value, string, error };
+ enum class result_type { value, string, error, matrix };
formula_result();
formula_result(const formula_result& r);
+ formula_result(formula_result&& r);
formula_result(double v);
formula_result(string_id_t strid);
formula_result(formula_error_t e);
@@ -44,6 +47,7 @@ public:
void set_value(double v);
void set_string(string_id_t strid);
void set_error(formula_error_t e);
+ void set_matrix(matrix mtx);
/**
* Get a numeric result value. The caller must make sure the result is of
@@ -71,6 +75,14 @@ public:
formula_error_t get_error() const;
/**
+ * Get a matrix value of the result. The caller must make sure that the
+ * result is of matrix type, else the behavior is undefined.
+ *
+ * @return matrix result value.
+ */
+ const matrix& get_matrix() const;
+
+ /**
* Get the type of result.
*
* @return enum value representing the result type.
@@ -93,7 +105,7 @@ public:
*/
void parse(iface::formula_model_access& cxt, const char* p, size_t n);
- formula_result& operator= (const formula_result& r);
+ formula_result& operator= (formula_result r);
bool operator== (const formula_result& r) const;
bool operator!= (const formula_result& r) const;
};
diff --git a/include/ixion/formula_tokens.hpp b/include/ixion/formula_tokens.hpp
index b60abac..de935fe 100644
--- a/include/ixion/formula_tokens.hpp
+++ b/include/ixion/formula_tokens.hpp
@@ -11,9 +11,9 @@
#include "ixion/address.hpp"
#include "ixion/table.hpp"
#include "ixion/formula_opcode.hpp"
+#include "ixion/formula_tokens_fwd.hpp"
#include <string>
-#include <vector>
namespace ixion {
@@ -53,7 +53,43 @@ public:
virtual void write_string(std::ostream& os) const;
};
-typedef std::vector<std::unique_ptr<formula_token>> formula_tokens_t;
+class IXION_DLLPUBLIC formula_tokens_store
+{
+ friend void intrusive_ptr_add_ref(formula_tokens_store*);
+ friend void intrusive_ptr_release(formula_tokens_store*);
+
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+ void add_ref();
+ void release_ref();
+
+ formula_tokens_store();
+
+public:
+
+ static formula_tokens_store_ptr_t create();
+
+ ~formula_tokens_store();
+
+ formula_tokens_store(const formula_tokens_store&) = delete;
+ formula_tokens_store& operator= (const formula_tokens_store&) = delete;
+
+ size_t get_reference_count() const;
+
+ formula_tokens_t& get();
+ const formula_tokens_t& get() const;
+};
+
+inline void intrusive_ptr_add_ref(formula_tokens_store* p)
+{
+ p->add_ref();
+}
+
+inline void intrusive_ptr_release(formula_tokens_store* p)
+{
+ p->release_ref();
+}
IXION_DLLPUBLIC bool operator== (const formula_tokens_t& left, const formula_tokens_t& right);
diff --git a/include/ixion/formula_tokens_fwd.hpp b/include/ixion/formula_tokens_fwd.hpp
new file mode 100644
index 0000000..2da6000
--- /dev/null
+++ b/include/ixion/formula_tokens_fwd.hpp
@@ -0,0 +1,26 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_FORMULA_TOKENS_FWD_HPP
+#define INCLUDED_IXION_FORMULA_TOKENS_FWD_HPP
+
+#include <boost/intrusive_ptr.hpp>
+#include <vector>
+#include <memory>
+
+namespace ixion {
+
+class formula_token;
+class formula_tokens_store;
+using formula_tokens_store_ptr_t = boost::intrusive_ptr<formula_tokens_store>;
+using formula_tokens_t = std::vector<std::unique_ptr<formula_token>>;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/info.hpp b/include/ixion/info.hpp
index aab3519..629c131 100644
--- a/include/ixion/info.hpp
+++ b/include/ixion/info.hpp
@@ -16,6 +16,9 @@ IXION_DLLPUBLIC int get_version_major();
IXION_DLLPUBLIC int get_version_minor();
IXION_DLLPUBLIC int get_version_micro();
+IXION_DLLPUBLIC int get_api_version_major();
+IXION_DLLPUBLIC int get_api_version_minor();
+
}
#endif
diff --git a/include/ixion/interface/Makefile.in b/include/ixion/interface/Makefile.in
index 6d2abf4..f5e180f 100644
--- a/include/ixion/interface/Makefile.in
+++ b/include/ixion/interface/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -182,11 +182,17 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
BOOST_LDPATH = @BOOST_LDPATH@
BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
@@ -217,8 +223,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IXION_API_VERSION = @IXION_API_VERSION@
+IXION_MAJOR_API_VERSION = @IXION_MAJOR_API_VERSION@
IXION_MAJOR_VERSION = @IXION_MAJOR_VERSION@
IXION_MICRO_VERSION = @IXION_MICRO_VERSION@
+IXION_MINOR_API_VERSION = @IXION_MINOR_API_VERSION@
IXION_MINOR_VERSION = @IXION_MINOR_VERSION@
IXION_VERSION = @IXION_VERSION@
LD = @LD@
diff --git a/include/ixion/interface/formula_model_access.hpp b/include/ixion/interface/formula_model_access.hpp
index 2093903..0208f5c 100644
--- a/include/ixion/interface/formula_model_access.hpp
+++ b/include/ixion/interface/formula_model_access.hpp
@@ -119,10 +119,6 @@ public:
virtual const table_handler* get_table_handler() const;
- virtual const formula_tokens_t* get_formula_tokens(sheet_t sheet, size_t identifier) const = 0;
- virtual const formula_tokens_t* get_shared_formula_tokens(sheet_t sheet, size_t identifier) const = 0;
- virtual abs_range_t get_shared_formula_range(sheet_t sheet, size_t identifier) const = 0;
-
virtual string_id_t append_string(const char* p, size_t n) = 0;
virtual string_id_t add_string(const char* p, size_t n) = 0;
virtual const std::string* get_string(string_id_t identifier) const = 0;
@@ -146,7 +142,7 @@ public:
*
* @return size of the sheet.
*/
- virtual sheet_size_t get_sheet_size(sheet_t sheet) const = 0;
+ virtual rc_size_t get_sheet_size(sheet_t sheet) const = 0;
/**
* Return the number of sheets.
diff --git a/include/ixion/matrix.hpp b/include/ixion/matrix.hpp
index 0737e51..ef5169a 100644
--- a/include/ixion/matrix.hpp
+++ b/include/ixion/matrix.hpp
@@ -9,11 +9,15 @@
#define INCLUDED_IXION_MATRIX_HPP
#include "ixion/env.hpp"
+#include "ixion/column_store_type.hpp"
#include <memory>
+#include <vector>
namespace ixion {
+class numeric_matrix;
+
/**
* 2-dimensional matrix consisting of elements of variable types. Each
* element can be numeric, string, or empty. This class is used to
@@ -26,13 +30,75 @@ class IXION_DLLPUBLIC matrix
public:
+ enum class element_type { numeric, string, boolean, empty };
+
+ struct element
+ {
+ element_type type;
+
+ union
+ {
+ double numeric;
+ bool boolean;
+ string_id_t string_id;
+ };
+ };
+
+ matrix();
matrix(size_t rows, size_t cols);
matrix(const matrix& other);
+ matrix(matrix&& other);
+ matrix(const numeric_matrix& other);
~matrix();
+ matrix& operator= (matrix other);
+
+ /**
+ * Determine if the entire matrix consists only of numeric value elements.
+ *
+ * @return true if the entire matrix consits only of numeric value
+ * elements, false otherwise.
+ */
+ bool is_numeric() const;
+
bool is_numeric(size_t row, size_t col) const;
double get_numeric(size_t row, size_t col) const;
void set(size_t row, size_t col, double val);
+
+ element get(size_t row, size_t col) const;
+
+ size_t row_size() const;
+ size_t col_size() const;
+
+ void swap(matrix& r);
+
+ numeric_matrix as_numeric() const;
+
+ bool operator== (const matrix& r) const;
+ bool operator!= (const matrix& r) const;
+};
+
+class IXION_DLLPUBLIC numeric_matrix
+{
+ friend class matrix;
+
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ numeric_matrix();
+ numeric_matrix(size_t rows, size_t cols);
+ numeric_matrix(std::vector<double> array, size_t rows, size_t cols);
+ numeric_matrix(numeric_matrix&& r);
+ ~numeric_matrix();
+
+ numeric_matrix& operator= (numeric_matrix other);
+
+ double& operator() (size_t row, size_t col);
+ const double& operator() (size_t row, size_t col) const;
+
+ void swap(numeric_matrix& r);
+
size_t row_size() const;
size_t col_size() const;
};
diff --git a/include/ixion/mem_str_buf.hpp b/include/ixion/mem_str_buf.hpp
index cc6aa1e..fc5417a 100644
--- a/include/ixion/mem_str_buf.hpp
+++ b/include/ixion/mem_str_buf.hpp
@@ -35,6 +35,7 @@ public:
void append(const char* p);
void set_start(const char* p);
void inc();
+ void dec();
void pop_front();
bool empty() const;
size_t size() const;
@@ -47,6 +48,7 @@ public:
char operator[] (size_t pos) const;
bool operator== (const mem_str_buf& r) const;
bool operator!= (const mem_str_buf& r) const { return !operator==(r); }
+ char back() const;
private:
const char* mp_buf;
diff --git a/include/ixion/model_context.hpp b/include/ixion/model_context.hpp
index 74c50c9..27a820f 100644
--- a/include/ixion/model_context.hpp
+++ b/include/ixion/model_context.hpp
@@ -14,7 +14,7 @@
#include "ixion/env.hpp"
#include <string>
-#include <deque>
+#include <memory>
namespace ixion {
@@ -32,6 +32,8 @@ class model_context_impl;
*/
class IXION_DLLPUBLIC model_context : public iface::formula_model_access
{
+ std::unique_ptr<model_context_impl> mp_impl;
+
public:
class IXION_DLLPUBLIC session_handler_factory
{
@@ -39,19 +41,6 @@ public:
virtual std::unique_ptr<iface::session_handler> create();
};
- struct shared_tokens
- {
- formula_tokens_t* tokens;
- abs_range_t range;
-
- shared_tokens();
- shared_tokens(formula_tokens_t* tokens);
- shared_tokens(const shared_tokens& r);
-
- bool operator== (const shared_tokens& r) const;
- };
- typedef std::vector<shared_tokens> shared_tokens_type;
-
model_context();
virtual ~model_context() override;
@@ -74,42 +63,46 @@ public:
virtual std::unique_ptr<iface::session_handler> create_session_handler() override;
virtual iface::table_handler* get_table_handler() override;
virtual const iface::table_handler* get_table_handler() const override;
- virtual const formula_tokens_t* get_formula_tokens(sheet_t sheet, size_t identifier) const override;
- virtual const formula_tokens_t* get_shared_formula_tokens(sheet_t sheet, size_t identifier) const override;
- virtual abs_range_t get_shared_formula_range(sheet_t sheet, size_t identifier) const override;
virtual string_id_t append_string(const char* p, size_t n) override;
virtual string_id_t add_string(const char* p, size_t n) override;
virtual const std::string* get_string(string_id_t identifier) const override;
virtual sheet_t get_sheet_index(const char* p, size_t n) const override;
virtual std::string get_sheet_name(sheet_t sheet) const override;
- virtual sheet_size_t get_sheet_size(sheet_t sheet) const override;
+ virtual rc_size_t get_sheet_size(sheet_t sheet) const override;
virtual size_t get_sheet_count() const override;
+ void set_config(const config& cfg);
+
double get_numeric_value_nowait(const abs_address_t& addr) const;
string_id_t get_string_identifier_nowait(const abs_address_t& addr) const;
- size_t add_formula_tokens(sheet_t sheet, formula_tokens_t* p);
- void set_shared_formula_range(sheet_t sheet, size_t identifier, const abs_range_t& range);
- size_t set_formula_tokens_shared(sheet_t sheet, size_t identifier);
- void remove_formula_tokens(sheet_t sheet, size_t identifier);
-
- void set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula, const char* p_range, size_t n_range,
- const formula_name_resolver& resolver);
- void set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula, const formula_name_resolver& resolver);
-
void erase_cell(const abs_address_t& addr);
void set_numeric_cell(const abs_address_t& addr, double val);
void set_boolean_cell(const abs_address_t& adr, bool val);
void set_string_cell(const abs_address_t& addr, const char* p, size_t n);
void set_string_cell(const abs_address_t& addr, string_id_t identifier);
- void set_formula_cell(const abs_address_t& addr, const char* p, size_t n, const formula_name_resolver& resolver);
- void set_formula_cell(const abs_address_t& addr, size_t identifier, bool shared);
+
+ /**
+ * Set a formula cell at a specified address.
+ *
+ * @param addr address at which to set a formula cell.
+ * @param tokens formula tokens to put into the formula cell.
+ */
+ void set_formula_cell(const abs_address_t& addr, formula_tokens_t tokens);
+
+ /**
+ * Set a formula cell at a specified address. This variant takes a
+ * formula tokens store that can be shared between multiple formula cell
+ * instances.
+ *
+ * @param addr address at which to set a formula cell.
+ * @param tokens formula tokens to put into the formula cell.
+ */
+ void set_formula_cell(const abs_address_t& addr, const formula_tokens_store_ptr_t& tokens);
+
+ void set_grouped_formula_cells(const abs_range_t& group_range, formula_tokens_t tokens);
abs_range_t get_data_range(sheet_t sheet) const;
@@ -165,9 +158,6 @@ public:
dirty_formula_cells_t get_all_formula_cells() const;
bool empty() const;
-
-private:
- model_context_impl* mp_impl;
};
}
diff --git a/include/ixion/module.hpp b/include/ixion/module.hpp
new file mode 100644
index 0000000..7b0d881
--- /dev/null
+++ b/include/ixion/module.hpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_MODULE_HPP
+#define INCLUDED_IXION_MODULE_HPP
+
+#include "ixion/env.hpp"
+
+namespace ixion { namespace draft {
+
+/**
+ * Initialize modules if exists.
+ */
+IXION_DLLPUBLIC void init_modules();
+
+class compute_engine;
+
+using create_compute_engine_t = compute_engine* (*)();
+using destroy_compute_engine_t = void (*)(const compute_engine*);
+
+struct module_def
+{
+ create_compute_engine_t create_compute_engine;
+ destroy_compute_engine_t destroy_compute_engine;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/types.hpp b/include/ixion/types.hpp
index e1cbb57..a859ffc 100644
--- a/include/ixion/types.hpp
+++ b/include/ixion/types.hpp
@@ -11,17 +11,24 @@
#include "ixion/env.hpp"
#include <cstdlib>
+#include <cstdint>
namespace ixion {
/** Column index type. */
-typedef int col_t;
+using col_t = int32_t;
/** Row index type. */
-typedef int row_t;
+using row_t = int32_t;
/** Sheet index type.*/
-typedef int sheet_t;
+using sheet_t = int32_t;
+
+/**
+ * Integer type that is large enough to store either a row or a column
+ * index.
+ */
+using rc_t = row_t;
/**
* String ID type.
@@ -30,7 +37,7 @@ typedef int sheet_t;
* get_string() method of ixion::iface::formula_model_access to get the
* actual string value.
*/
-typedef unsigned long string_id_t;
+using string_id_t = uint64_t;
/**
* Special sheet ID that represents a global scope, as opposed to a
@@ -104,28 +111,65 @@ enum class formula_name_resolver_t
/**
* Formula error types.
+ *
+ * @see get_formula_error_name
*/
-enum class formula_error_t
+enum class formula_error_t : uint8_t
{
- no_error = 0,
+ no_error = 0,
ref_result_not_available = 1,
- division_by_zero = 2,
- invalid_expression = 3,
- name_not_found = 4,
- stack_error = 5,
- general_error = 999,
+ division_by_zero = 2,
+ invalid_expression = 3,
+ name_not_found = 4,
+ no_range_intersection = 5,
+ invalid_value_type = 6,
+
+ no_result_error = 253, // internal only error
+ stack_error = 254, // internal only error
+ general_error = 255, // internal only error
};
-struct IXION_DLLPUBLIC sheet_size_t
+/**
+ * This structure stores a 2-dimensional size information.
+ */
+struct IXION_DLLPUBLIC rc_size_t
{
row_t row;
col_t column;
- sheet_size_t();
- sheet_size_t(const sheet_size_t& other);
- sheet_size_t(row_t _row, col_t _column);
+ rc_size_t();
+ rc_size_t(const rc_size_t& other);
+ rc_size_t(row_t _row, col_t _column);
+ ~rc_size_t();
+
+ rc_size_t& operator= (const rc_size_t& other);
};
+/**
+ * This strcuture stores information about grouped formula cells. All
+ * formula cells belonging to the same group should return the same set of
+ * values.
+ */
+struct IXION_DLLPUBLIC formula_group_t
+{
+ rc_size_t size;
+ uintptr_t identity;
+ bool grouped;
+
+ formula_group_t();
+ formula_group_t(const formula_group_t& r);
+ formula_group_t(const rc_size_t& group_size, uintptr_t identity, bool grouped);
+ ~formula_group_t();
+
+ formula_group_t& operator= (const formula_group_t& other);
+};
+
+/**
+ * Get a string representation of a formula error type.
+ *
+ * @param fe enum value representing a formula error type.
+ * @return string representation of the formula error type.
+ */
IXION_DLLPUBLIC const char* get_formula_error_name(formula_error_t fe);
}
diff --git a/ltmain.sh b/ltmain.sh
index 147d758..a736cf9 100644
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -31,7 +31,7 @@
PROGRAM=libtool
PACKAGE=libtool
-VERSION="2.4.6 Debian-2.4.6-0.1"
+VERSION="2.4.6 Debian-2.4.6-2"
package_revision=2.4.6
@@ -2068,7 +2068,7 @@ include the following information:
compiler: $LTCC
compiler flags: $LTCFLAGS
linker: $LD (gnu? $with_gnu_ld)
- version: $progname (GNU libtool) 2.4.6
+ version: $progname $scriptversion Debian-2.4.6-2
automake: `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
autoconf: `($AUTOCONF --version) 2>/dev/null |$SED 1q`
diff --git a/m4/libtool.m4 b/m4/libtool.m4
index 10ab284..ee80844 100644
--- a/m4/libtool.m4
+++ b/m4/libtool.m4
@@ -728,7 +728,6 @@ _LT_CONFIG_SAVE_COMMANDS([
cat <<_LT_EOF >> "$cfgfile"
#! $SHELL
# Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
# Provide generalized library-building support services.
diff --git a/src/Makefile.in b/src/Makefile.in
index ac72d53..ccd4b7a 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -466,11 +466,17 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
BOOST_LDPATH = @BOOST_LDPATH@
BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
@@ -501,8 +507,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IXION_API_VERSION = @IXION_API_VERSION@
+IXION_MAJOR_API_VERSION = @IXION_MAJOR_API_VERSION@
IXION_MAJOR_VERSION = @IXION_MAJOR_VERSION@
IXION_MICRO_VERSION = @IXION_MICRO_VERSION@
+IXION_MINOR_API_VERSION = @IXION_MINOR_API_VERSION@
IXION_MINOR_VERSION = @IXION_MINOR_VERSION@
IXION_VERSION = @IXION_VERSION@
LD = @LD@
diff --git a/src/ixion_formula_tokenizer.cpp b/src/ixion_formula_tokenizer.cpp
index 6a09097..100a452 100644
--- a/src/ixion_formula_tokenizer.cpp
+++ b/src/ixion_formula_tokenizer.cpp
@@ -17,6 +17,7 @@
#include "ixion/formula.hpp"
#include "ixion/model_context.hpp"
#include "ixion/formula_name_resolver.hpp"
+#include "ixion/config.hpp"
using std::cout;
using std::endl;
@@ -30,6 +31,10 @@ void tokenize_formula(const std::string& formula)
std::unique_ptr<formula_name_resolver> resolver =
formula_name_resolver::get(formula_name_resolver_t::excel_a1, &cxt);
+ config cfg = cxt.get_config();
+ cfg.sep_function_arg = ',';
+ cxt.set_config(cfg);
+
abs_address_t pos;
formula_tokens_t tokens = parse_formula_string(
diff --git a/src/libixion/Makefile.am b/src/libixion/Makefile.am
index 348cef4..904a111 100644
--- a/src/libixion/Makefile.am
+++ b/src/libixion/Makefile.am
@@ -1,11 +1,26 @@
-AM_CPPFLAGS = -I$(top_srcdir)/include -DIXION_BUILD $(MDDS_CFLAGS) $(BOOST_CPPFLAGS)
-check_PROGRAMS = ixion-test
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/include \
+ -DIXION_BUILD \
+ $(MDDS_CFLAGS) \
+ $(BOOST_CPPFLAGS)
+
+if BUILD_CUDA
+
+AM_CPPFLAGS += -DBUILD_CUDA
+
+endif # BUILD_CUDA
+
+check_PROGRAMS = ixion-test ixion-test-track-deps compute-engine-test
lib_LTLIBRARIES = libixion-@IXION_API_VERSION@.la
libixion_@IXION_API_VERSION@_la_SOURCES = \
address.cpp \
+ address_iterator.cpp \
+ calc_status.hpp \
+ calc_status.cpp \
cell.cpp \
+ compute_engine.cpp \
concrete_formula_tokens.hpp \
concrete_formula_tokens.cpp \
config.cpp \
@@ -30,6 +45,8 @@ libixion_@IXION_API_VERSION@_la_SOURCES = \
function_objects.hpp \
function_objects.cpp \
global.cpp \
+ grouped_ranges.hpp \
+ grouped_ranges.cpp \
info.cpp \
lexer_tokens.hpp \
lexer_tokens.cpp \
@@ -37,6 +54,7 @@ libixion_@IXION_API_VERSION@_la_SOURCES = \
mem_str_buf.cpp \
model_context.cpp \
model_types.hpp \
+ module.cpp \
cell_listener_tracker.cpp \
table.cpp \
types.cpp \
@@ -44,6 +62,21 @@ libixion_@IXION_API_VERSION@_la_SOURCES = \
workbook.cpp \
interface.cpp
+if BUILD_CUDA
+
+# CUDA module
+
+pkglib_LTLIBRARIES = ixion-@IXION_API_VERSION@-cuda.la
+ixion_@IXION_API_VERSION@_cuda_la_SOURCES = \
+ compute_engine_cuda.hpp \
+ compute_engine_cuda.cpp
+
+ixion_@IXION_API_VERSION@_cuda_la_LDFLAGS = -module -avoid-version -export-symbols-regex register_module
+ixion_@IXION_API_VERSION@_cuda_la_LIBADD = \
+ libixion-@IXION_API_VERSION@.la
+
+endif # BUILD_CUDA
+
if IXION_THREADS
libixion_@IXION_API_VERSION@_la_SOURCES += \
@@ -52,8 +85,14 @@ libixion_@IXION_API_VERSION@_la_SOURCES += \
endif
-libixion_@IXION_API_VERSION@_la_LDFLAGS = -no-undefined
-libixion_@IXION_API_VERSION@_la_LIBADD =
+libixion_@IXION_API_VERSION@_la_LDFLAGS = \
+ -no-undefined \
+ $(BOOST_FILESYSTEM_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+libixion_@IXION_API_VERSION@_la_LIBADD = \
+ $(BOOST_FILESYSTEM_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
EXTRA_DIST = makefile.mk
@@ -62,4 +101,15 @@ ixion_test_LDADD = \
libixion-@IXION_API_VERSION@.la \
$(BOOST_PROGRAM_OPTIONS_LIBS)
-TESTS = ixion-test
+ixion_test_track_deps_SOURCES = ixion_test_track_deps.cpp
+ixion_test_track_deps_LDADD = \
+ libixion-@IXION_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+compute_engine_test_SOURCES = compute_engine_test.cpp
+compute_engine_test_LDADD = \
+ libixion-@IXION_API_VERSION@.la
+
+AM_TESTS_ENVIRONMENT = IXION_MODULE_PATH=.libs; export IXION_MODULE_PATH;
+
+TESTS = ixion-test ixion-test-track-deps compute-engine-test
diff --git a/src/libixion/Makefile.in b/src/libixion/Makefile.in
index 40099aa..38de8ed 100644
--- a/src/libixion/Makefile.in
+++ b/src/libixion/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -88,12 +88,15 @@ PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
-check_PROGRAMS = ixion-test$(EXEEXT)
-@IXION_THREADS_TRUE@am__append_1 = \
+@BUILD_CUDA_TRUE@am__append_1 = -DBUILD_CUDA
+check_PROGRAMS = ixion-test$(EXEEXT) ixion-test-track-deps$(EXEEXT) \
+ compute-engine-test$(EXEEXT)
+@IXION_THREADS_TRUE@am__append_2 = \
@IXION_THREADS_TRUE@ cell_queue_manager.hpp \
@IXION_THREADS_TRUE@ cell_queue_manager.cpp
-TESTS = ixion-test$(EXEEXT)
+TESTS = ixion-test$(EXEEXT) ixion-test-track-deps$(EXEEXT) \
+ compute-engine-test$(EXEEXT)
subdir = src/libixion
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
@@ -135,11 +138,32 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
-am__installdirs = "$(DESTDIR)$(libdir)"
-LTLIBRARIES = $(lib_LTLIBRARIES)
-libixion_@IXION_API_VERSION@_la_DEPENDENCIES =
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(pkglib_LTLIBRARIES)
+@BUILD_CUDA_TRUE@ixion_@IXION_API_VERSION@_cuda_la_DEPENDENCIES = \
+@BUILD_CUDA_TRUE@ libixion-@IXION_API_VERSION@.la
+am__ixion_@IXION_API_VERSION@_cuda_la_SOURCES_DIST = \
+ compute_engine_cuda.hpp compute_engine_cuda.cpp
+@BUILD_CUDA_TRUE@am_ixion_@IXION_API_VERSION@_cuda_la_OBJECTS = \
+@BUILD_CUDA_TRUE@ compute_engine_cuda.lo
+ixion_@IXION_API_VERSION@_cuda_la_OBJECTS = \
+ $(am_ixion_@IXION_API_VERSION@_cuda_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+ixion_@IXION_API_VERSION@_cuda_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
+ $(ixion_@IXION_API_VERSION@_cuda_la_LDFLAGS) $(LDFLAGS) -o $@
+@BUILD_CUDA_TRUE@am_ixion_@IXION_API_VERSION@_cuda_la_rpath = -rpath \
+@BUILD_CUDA_TRUE@ $(pkglibdir)
+am__DEPENDENCIES_1 =
+libixion_@IXION_API_VERSION@_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
am__libixion_@IXION_API_VERSION@_la_SOURCES_DIST = address.cpp \
- cell.cpp concrete_formula_tokens.hpp \
+ address_iterator.cpp calc_status.hpp calc_status.cpp cell.cpp \
+ compute_engine.cpp concrete_formula_tokens.hpp \
concrete_formula_tokens.cpp config.cpp depends_tracker.hpp \
depends_tracker.cpp exceptions.cpp formula.cpp \
formula_function_opcode.cpp formula_functions.hpp \
@@ -148,36 +172,42 @@ am__libixion_@IXION_API_VERSION@_la_SOURCES_DIST = address.cpp \
formula_name_resolver.cpp formula_parser.hpp \
formula_parser.cpp formula_result.cpp formula_tokens.cpp \
formula_value_stack.hpp formula_value_stack.cpp \
- function_objects.hpp function_objects.cpp global.cpp info.cpp \
+ function_objects.hpp function_objects.cpp global.cpp \
+ grouped_ranges.hpp grouped_ranges.cpp info.cpp \
lexer_tokens.hpp lexer_tokens.cpp matrix.cpp mem_str_buf.cpp \
- model_context.cpp model_types.hpp cell_listener_tracker.cpp \
- table.cpp types.cpp workbook.hpp workbook.cpp interface.cpp \
- cell_queue_manager.hpp cell_queue_manager.cpp
+ model_context.cpp model_types.hpp module.cpp \
+ cell_listener_tracker.cpp table.cpp types.cpp workbook.hpp \
+ workbook.cpp interface.cpp cell_queue_manager.hpp \
+ cell_queue_manager.cpp
@IXION_THREADS_TRUE@am__objects_1 = cell_queue_manager.lo
-am_libixion_@IXION_API_VERSION@_la_OBJECTS = address.lo cell.lo \
+am_libixion_@IXION_API_VERSION@_la_OBJECTS = address.lo \
+ address_iterator.lo calc_status.lo cell.lo compute_engine.lo \
concrete_formula_tokens.lo config.lo depends_tracker.lo \
exceptions.lo formula.lo formula_function_opcode.lo \
formula_functions.lo formula_interpreter.lo formula_lexer.lo \
formula_name_resolver.lo formula_parser.lo formula_result.lo \
formula_tokens.lo formula_value_stack.lo function_objects.lo \
- global.lo info.lo lexer_tokens.lo matrix.lo mem_str_buf.lo \
- model_context.lo cell_listener_tracker.lo table.lo types.lo \
- workbook.lo interface.lo $(am__objects_1)
+ global.lo grouped_ranges.lo info.lo lexer_tokens.lo matrix.lo \
+ mem_str_buf.lo model_context.lo module.lo \
+ cell_listener_tracker.lo table.lo types.lo workbook.lo \
+ interface.lo $(am__objects_1)
libixion_@IXION_API_VERSION@_la_OBJECTS = \
$(am_libixion_@IXION_API_VERSION@_la_OBJECTS)
-AM_V_lt = $(am__v_lt_@AM_V@)
-am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
-am__v_lt_0 = --silent
-am__v_lt_1 =
libixion_@IXION_API_VERSION@_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
$(AM_CXXFLAGS) $(CXXFLAGS) \
$(libixion_@IXION_API_VERSION@_la_LDFLAGS) $(LDFLAGS) -o $@
+am_compute_engine_test_OBJECTS = compute_engine_test.$(OBJEXT)
+compute_engine_test_OBJECTS = $(am_compute_engine_test_OBJECTS)
+compute_engine_test_DEPENDENCIES = libixion-@IXION_API_VERSION@.la
am_ixion_test_OBJECTS = ixion_test.$(OBJEXT)
ixion_test_OBJECTS = $(am_ixion_test_OBJECTS)
-am__DEPENDENCIES_1 =
ixion_test_DEPENDENCIES = libixion-@IXION_API_VERSION@.la \
$(am__DEPENDENCIES_1)
+am_ixion_test_track_deps_OBJECTS = ixion_test_track_deps.$(OBJEXT)
+ixion_test_track_deps_OBJECTS = $(am_ixion_test_track_deps_OBJECTS)
+ixion_test_track_deps_DEPENDENCIES = libixion-@IXION_API_VERSION@.la \
+ $(am__DEPENDENCIES_1)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -230,10 +260,14 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
-SOURCES = $(libixion_@IXION_API_VERSION@_la_SOURCES) \
- $(ixion_test_SOURCES)
-DIST_SOURCES = $(am__libixion_@IXION_API_VERSION@_la_SOURCES_DIST) \
- $(ixion_test_SOURCES)
+SOURCES = $(ixion_@IXION_API_VERSION@_cuda_la_SOURCES) \
+ $(libixion_@IXION_API_VERSION@_la_SOURCES) \
+ $(compute_engine_test_SOURCES) $(ixion_test_SOURCES) \
+ $(ixion_test_track_deps_SOURCES)
+DIST_SOURCES = $(am__ixion_@IXION_API_VERSION@_cuda_la_SOURCES_DIST) \
+ $(am__libixion_@IXION_API_VERSION@_la_SOURCES_DIST) \
+ $(compute_engine_test_SOURCES) $(ixion_test_SOURCES) \
+ $(ixion_test_track_deps_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -448,11 +482,17 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
BOOST_LDPATH = @BOOST_LDPATH@
BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
@@ -483,8 +523,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IXION_API_VERSION = @IXION_API_VERSION@
+IXION_MAJOR_API_VERSION = @IXION_MAJOR_API_VERSION@
IXION_MAJOR_VERSION = @IXION_MAJOR_VERSION@
IXION_MICRO_VERSION = @IXION_MICRO_VERSION@
+IXION_MINOR_API_VERSION = @IXION_MINOR_API_VERSION@
IXION_MINOR_VERSION = @IXION_MINOR_VERSION@
IXION_VERSION = @IXION_VERSION@
LD = @LD@
@@ -590,30 +632,62 @@ target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
-AM_CPPFLAGS = -I$(top_srcdir)/include -DIXION_BUILD $(MDDS_CFLAGS) $(BOOST_CPPFLAGS)
+AM_CPPFLAGS = -I$(top_srcdir)/include -DIXION_BUILD $(MDDS_CFLAGS) \
+ $(BOOST_CPPFLAGS) $(am__append_1)
lib_LTLIBRARIES = libixion-@IXION_API_VERSION@.la
-libixion_@IXION_API_VERSION@_la_SOURCES = address.cpp cell.cpp \
- concrete_formula_tokens.hpp concrete_formula_tokens.cpp \
- config.cpp depends_tracker.hpp depends_tracker.cpp \
- exceptions.cpp formula.cpp formula_function_opcode.cpp \
- formula_functions.hpp formula_functions.cpp \
- formula_interpreter.hpp formula_interpreter.cpp \
- formula_lexer.hpp formula_lexer.cpp formula_name_resolver.cpp \
- formula_parser.hpp formula_parser.cpp formula_result.cpp \
- formula_tokens.cpp formula_value_stack.hpp \
- formula_value_stack.cpp function_objects.hpp \
- function_objects.cpp global.cpp info.cpp lexer_tokens.hpp \
- lexer_tokens.cpp matrix.cpp mem_str_buf.cpp model_context.cpp \
- model_types.hpp cell_listener_tracker.cpp table.cpp types.cpp \
- workbook.hpp workbook.cpp interface.cpp $(am__append_1)
-libixion_@IXION_API_VERSION@_la_LDFLAGS = -no-undefined
-libixion_@IXION_API_VERSION@_la_LIBADD =
+libixion_@IXION_API_VERSION@_la_SOURCES = address.cpp \
+ address_iterator.cpp calc_status.hpp calc_status.cpp cell.cpp \
+ compute_engine.cpp concrete_formula_tokens.hpp \
+ concrete_formula_tokens.cpp config.cpp depends_tracker.hpp \
+ depends_tracker.cpp exceptions.cpp formula.cpp \
+ formula_function_opcode.cpp formula_functions.hpp \
+ formula_functions.cpp formula_interpreter.hpp \
+ formula_interpreter.cpp formula_lexer.hpp formula_lexer.cpp \
+ formula_name_resolver.cpp formula_parser.hpp \
+ formula_parser.cpp formula_result.cpp formula_tokens.cpp \
+ formula_value_stack.hpp formula_value_stack.cpp \
+ function_objects.hpp function_objects.cpp global.cpp \
+ grouped_ranges.hpp grouped_ranges.cpp info.cpp \
+ lexer_tokens.hpp lexer_tokens.cpp matrix.cpp mem_str_buf.cpp \
+ model_context.cpp model_types.hpp module.cpp \
+ cell_listener_tracker.cpp table.cpp types.cpp workbook.hpp \
+ workbook.cpp interface.cpp $(am__append_2)
+
+# CUDA module
+@BUILD_CUDA_TRUE@pkglib_LTLIBRARIES = ixion-@IXION_API_VERSION@-cuda.la
+@BUILD_CUDA_TRUE@ixion_@IXION_API_VERSION@_cuda_la_SOURCES = \
+@BUILD_CUDA_TRUE@ compute_engine_cuda.hpp \
+@BUILD_CUDA_TRUE@ compute_engine_cuda.cpp
+
+@BUILD_CUDA_TRUE@ixion_@IXION_API_VERSION@_cuda_la_LDFLAGS = -module -avoid-version -export-symbols-regex register_module
+@BUILD_CUDA_TRUE@ixion_@IXION_API_VERSION@_cuda_la_LIBADD = \
+@BUILD_CUDA_TRUE@ libixion-@IXION_API_VERSION@.la
+
+libixion_@IXION_API_VERSION@_la_LDFLAGS = \
+ -no-undefined \
+ $(BOOST_FILESYSTEM_LDFLAGS) \
+ $(BOOST_SYSTEM_LDFLAGS)
+
+libixion_@IXION_API_VERSION@_la_LIBADD = \
+ $(BOOST_FILESYSTEM_LIBS) \
+ $(BOOST_SYSTEM_LIBS)
+
EXTRA_DIST = makefile.mk
ixion_test_SOURCES = ixion_test.cpp
ixion_test_LDADD = \
libixion-@IXION_API_VERSION@.la \
$(BOOST_PROGRAM_OPTIONS_LIBS)
+ixion_test_track_deps_SOURCES = ixion_test_track_deps.cpp
+ixion_test_track_deps_LDADD = \
+ libixion-@IXION_API_VERSION@.la \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+compute_engine_test_SOURCES = compute_engine_test.cpp
+compute_engine_test_LDADD = \
+ libixion-@IXION_API_VERSION@.la
+
+AM_TESTS_ENVIRONMENT = IXION_MODULE_PATH=.libs; export IXION_MODULE_PATH;
all: all-am
.SUFFIXES:
@@ -685,6 +759,44 @@ clean-libLTLIBRARIES:
rm -f $${locs}; \
}
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+ixion-@IXION_API_VERSION@-cuda.la: $(ixion_@IXION_API_VERSION@_cuda_la_OBJECTS) $(ixion_@IXION_API_VERSION@_cuda_la_DEPENDENCIES) $(EXTRA_ixion_@IXION_API_VERSION@_cuda_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(ixion_@IXION_API_VERSION@_cuda_la_LINK) $(am_ixion_@IXION_API_VERSION@_cuda_la_rpath) $(ixion_@IXION_API_VERSION@_cuda_la_OBJECTS) $(ixion_@IXION_API_VERSION@_cuda_la_LIBADD) $(LIBS)
+
libixion-@IXION_API_VERSION@.la: $(libixion_@IXION_API_VERSION@_la_OBJECTS) $(libixion_@IXION_API_VERSION@_la_DEPENDENCIES) $(EXTRA_libixion_@IXION_API_VERSION@_la_DEPENDENCIES)
$(AM_V_CXXLD)$(libixion_@IXION_API_VERSION@_la_LINK) -rpath $(libdir) $(libixion_@IXION_API_VERSION@_la_OBJECTS) $(libixion_@IXION_API_VERSION@_la_LIBADD) $(LIBS)
@@ -697,10 +809,18 @@ clean-checkPROGRAMS:
echo " rm -f" $$list; \
rm -f $$list
+compute-engine-test$(EXEEXT): $(compute_engine_test_OBJECTS) $(compute_engine_test_DEPENDENCIES) $(EXTRA_compute_engine_test_DEPENDENCIES)
+ @rm -f compute-engine-test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(compute_engine_test_OBJECTS) $(compute_engine_test_LDADD) $(LIBS)
+
ixion-test$(EXEEXT): $(ixion_test_OBJECTS) $(ixion_test_DEPENDENCIES) $(EXTRA_ixion_test_DEPENDENCIES)
@rm -f ixion-test$(EXEEXT)
$(AM_V_CXXLD)$(CXXLINK) $(ixion_test_OBJECTS) $(ixion_test_LDADD) $(LIBS)
+ixion-test-track-deps$(EXEEXT): $(ixion_test_track_deps_OBJECTS) $(ixion_test_track_deps_DEPENDENCIES) $(EXTRA_ixion_test_track_deps_DEPENDENCIES)
+ @rm -f ixion-test-track-deps$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(ixion_test_track_deps_OBJECTS) $(ixion_test_track_deps_LDADD) $(LIBS)
+
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -708,9 +828,14 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address_iterator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/calc_status.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cell.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cell_listener_tracker.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cell_queue_manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compute_engine.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compute_engine_cuda.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compute_engine_test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/concrete_formula_tokens.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/depends_tracker.Plo@am__quote@
@@ -727,13 +852,16 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/formula_value_stack.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/function_objects.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/global.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grouped_ranges.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/info.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ixion_test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ixion_test_track_deps.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexer_tokens.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/matrix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem_str_buf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/model_context.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/module.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/table.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/types.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workbook.Plo@am__quote@
@@ -965,6 +1093,20 @@ ixion-test.log: ixion-test$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
+ixion-test-track-deps.log: ixion-test-track-deps$(EXEEXT)
+ @p='ixion-test-track-deps$(EXEEXT)'; \
+ b='ixion-test-track-deps'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+compute-engine-test.log: compute-engine-test$(EXEEXT)
+ @p='compute-engine-test$(EXEEXT)'; \
+ b='compute-engine-test'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
.test.log:
@p='$<'; \
$(am__set_b); \
@@ -1016,7 +1158,7 @@ check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES)
installdirs:
- for dir in "$(DESTDIR)$(libdir)"; do \
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkglibdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -1055,7 +1197,7 @@ maintainer-clean-generic:
clean: clean-am
clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \
- clean-libtool mostlyclean-am
+ clean-libtool clean-pkglibLTLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
@@ -1081,7 +1223,7 @@ install-dvi: install-dvi-am
install-dvi-am:
-install-exec-am: install-libLTLIBRARIES
+install-exec-am: install-libLTLIBRARIES install-pkglibLTLIBRARIES
install-html: install-html-am
@@ -1121,25 +1263,26 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-libLTLIBRARIES
+uninstall-am: uninstall-libLTLIBRARIES uninstall-pkglibLTLIBRARIES
.MAKE: check-am install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \
- clean-libtool cscopelist-am ctags ctags-am distclean \
- distclean-compile distclean-generic distclean-libtool \
- distclean-tags distdir dvi dvi-am html html-am info info-am \
- install install-am install-data install-data-am install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am \
- install-libLTLIBRARIES install-man install-pdf install-pdf-am \
- install-ps install-ps-am install-strip installcheck \
- installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-compile \
- mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
- recheck tags tags-am uninstall uninstall-am \
- uninstall-libLTLIBRARIES
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-pkglibLTLIBRARIES install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am uninstall-libLTLIBRARIES \
+ uninstall-pkglibLTLIBRARIES
.PRECIOUS: Makefile
diff --git a/src/libixion/address.cpp b/src/libixion/address.cpp
index 4c5b9f9..25e1a3a 100644
--- a/src/libixion/address.cpp
+++ b/src/libixion/address.cpp
@@ -213,6 +213,67 @@ bool operator< (const address_t& left, const address_t& right)
return left.column < right.column;
}
+abs_rc_address_t::abs_rc_address_t()
+{
+}
+
+abs_rc_address_t::abs_rc_address_t(init_invalid) :
+ row(-1), column(-1) {}
+
+abs_rc_address_t::abs_rc_address_t(row_t row, col_t column) :
+ row(row), column(column) {}
+
+abs_rc_address_t::abs_rc_address_t(const abs_rc_address_t& r) :
+ row(r.row), column(r.column) {}
+
+bool abs_rc_address_t::valid() const
+{
+ return row >= 0 && column >= 0 && row <= row_unset && column <= column_unset;
+}
+
+size_t abs_rc_address_t::hash::operator() (const abs_rc_address_t& addr) const
+{
+ size_t hv = addr.column;
+ hv <<= 16;
+ hv += addr.row;
+ return hv;
+}
+
+bool operator== (const abs_rc_address_t& left, const abs_rc_address_t& right)
+{
+ return left.row == right.row && left.column == right.column;
+}
+
+bool operator!= (const abs_rc_address_t& left, const abs_rc_address_t& right)
+{
+ return !operator==(left, right);
+}
+
+bool operator< (const abs_rc_address_t& left, const abs_rc_address_t& right)
+{
+ if (left.row != right.row)
+ return left.row < right.row;
+
+ return left.column < right.column;
+}
+
+rc_address_t::rc_address_t() :
+ row(0), column(0), abs_row(true), abs_column(true) {}
+
+rc_address_t::rc_address_t(row_t row, col_t column, bool abs_row, bool abs_column) :
+ row(row), column(column), abs_row(abs_row), abs_column(abs_column) {}
+
+rc_address_t::rc_address_t(const rc_address_t& r) :
+ row(r.row), column(r.column), abs_row(r.abs_row), abs_column(r.abs_column) {}
+
+size_t rc_address_t::hash::operator()(const rc_address_t& addr) const
+{
+ size_t hv = addr.column;
+ hv <<= 16;
+ hv += addr.row;
+ return hv;
+}
+
abs_range_t::abs_range_t() {}
abs_range_t::abs_range_t(init_invalid) :
first(abs_address_t::invalid), last(abs_address_t::invalid) {}
@@ -228,24 +289,24 @@ bool abs_range_t::valid() const
return first.valid() && last.valid();
}
-void abs_range_t::set_whole_column()
+void abs_range_t::set_all_columns()
{
first.column = column_unset;
last.column = column_unset;
}
-void abs_range_t::set_whole_row()
+void abs_range_t::set_all_rows()
{
first.row = row_unset;
last.row = row_unset;
}
-bool abs_range_t::whole_column() const
+bool abs_range_t::all_columns() const
{
return first.column == column_unset && last.column == column_unset;
}
-bool abs_range_t::whole_row() const
+bool abs_range_t::all_rows() const
{
return first.row == row_unset && last.row == row_unset;
}
@@ -274,6 +335,66 @@ bool operator<(const abs_range_t& left, const abs_range_t& right)
return left.last < right.last;
}
+abs_rc_range_t::abs_rc_range_t() {}
+abs_rc_range_t::abs_rc_range_t(init_invalid) :
+ first(abs_rc_address_t::invalid), last(abs_rc_address_t::invalid) {}
+
+size_t abs_rc_range_t::hash::operator() (const abs_rc_range_t& range) const
+{
+ abs_rc_address_t::hash adr_hash;
+ return adr_hash(range.first) + 65536*adr_hash(range.last);
+}
+
+bool abs_rc_range_t::valid() const
+{
+ return first.valid() && last.valid();
+}
+
+void abs_rc_range_t::set_all_columns()
+{
+ first.column = column_unset;
+ last.column = column_unset;
+}
+
+void abs_rc_range_t::set_all_rows()
+{
+ first.row = row_unset;
+ last.row = row_unset;
+}
+
+bool abs_rc_range_t::all_columns() const
+{
+ return first.column == column_unset && last.column == column_unset;
+}
+
+bool abs_rc_range_t::all_rows() const
+{
+ return first.row == row_unset && last.row == row_unset;
+}
+
+bool abs_rc_range_t::contains(const abs_rc_address_t& addr) const
+{
+ return first.row <= addr.row && addr.row <= last.row &&
+ first.column <= addr.column && addr.column <= last.column;
+}
+
+bool operator==(const abs_rc_range_t& left, const abs_rc_range_t& right)
+{
+ return left.first == right.first && left.last == right.last;
+}
+
+bool operator!=(const abs_rc_range_t& left, const abs_rc_range_t& right)
+{
+ return !operator==(left, right);
+}
+
+bool operator<(const abs_rc_range_t& left, const abs_rc_range_t& right)
+{
+ if (left.first != right.first)
+ return left.first < right.first;
+ return left.last < right.last;
+}
+
range_t::range_t() {}
range_t::range_t(const address_t& _first, const address_t& _last) :
first(_first), last(_last) {}
@@ -286,24 +407,24 @@ bool range_t::valid() const
return first.valid() && last.valid();
}
-void range_t::set_whole_column()
+void range_t::set_all_columns()
{
first.column = column_unset;
last.column = column_unset;
}
-void range_t::set_whole_row()
+void range_t::set_all_rows()
{
first.row = row_unset;
last.row = row_unset;
}
-bool range_t::whole_column() const
+bool range_t::all_columns() const
{
return first.column == column_unset && last.column == column_unset;
}
-bool range_t::whole_row() const
+bool range_t::all_rows() const
{
return first.row == row_unset && last.row == row_unset;
}
diff --git a/src/libixion/address_iterator.cpp b/src/libixion/address_iterator.cpp
new file mode 100644
index 0000000..ce2db06
--- /dev/null
+++ b/src/libixion/address_iterator.cpp
@@ -0,0 +1,316 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ixion/address_iterator.hpp"
+#include "ixion/address.hpp"
+#include "ixion/global.hpp"
+
+#include <cassert>
+#include <functional>
+
+namespace ixion {
+
+namespace {
+
+bool inc_sheet(const abs_range_t& range, abs_address_t& pos)
+{
+ if (pos.sheet < range.last.sheet)
+ {
+ ++pos.sheet;
+ pos.row = range.first.row;
+ pos.column = range.first.column;
+ return true;
+ }
+
+ return false;
+}
+
+bool dec_sheet(const abs_range_t& range, abs_address_t& pos)
+{
+ if (range.first.sheet < pos.sheet)
+ {
+ --pos.sheet;
+ pos.row = range.last.row;
+ pos.column = range.last.column;
+ return true;
+ }
+
+ return false;
+}
+
+void inc_vertical(const abs_range_t& range, abs_address_t& pos, bool& end_pos)
+{
+ if (end_pos)
+ throw std::out_of_range("attempting to increment past the end position.");
+
+ if (pos.row < range.last.row)
+ {
+ ++pos.row;
+ return;
+ }
+
+ if (pos.column < range.last.column)
+ {
+ ++pos.column;
+ pos.row = range.first.row;
+ return;
+ }
+
+ if (inc_sheet(range, pos))
+ return;
+
+ assert(pos == range.last);
+ end_pos = true;
+}
+
+void dec_vertical(const abs_range_t& range, abs_address_t& pos, bool& end_pos)
+{
+ if (end_pos)
+ {
+ end_pos = false;
+ assert(pos == range.last);
+ return;
+ }
+
+ if (range.first.row < pos.row)
+ {
+ --pos.row;
+ return;
+ }
+
+ assert(pos.row == range.first.row);
+
+ if (range.first.column < pos.column)
+ {
+ --pos.column;
+ pos.row = range.last.row;
+ return;
+ }
+
+ assert(pos.column == range.first.column);
+
+ if (dec_sheet(range, pos))
+ return;
+
+ assert(pos == range.first);
+ throw std::out_of_range("Attempting to decrement beyond the first position.");
+}
+
+void inc_horizontal(const abs_range_t& range, abs_address_t& pos, bool& end_pos)
+{
+ if (end_pos)
+ throw std::out_of_range("attempting to increment past the end position.");
+
+ if (pos.column < range.last.column)
+ {
+ ++pos.column;
+ return;
+ }
+
+ if (pos.row < range.last.row)
+ {
+ ++pos.row;
+ pos.column = range.first.column;
+ return;
+ }
+
+ if (inc_sheet(range, pos))
+ return;
+
+ assert(pos == range.last);
+ end_pos = true;
+}
+
+void dec_horizontal(const abs_range_t& range, abs_address_t& pos, bool& end_pos)
+{
+ if (end_pos)
+ {
+ end_pos = false;
+ assert(pos == range.last);
+ return;
+ }
+
+ if (range.first.column < pos.column)
+ {
+ --pos.column;
+ return;
+ }
+
+ assert(pos.column == range.first.column);
+
+ if (range.first.row < pos.row)
+ {
+ --pos.row;
+ pos.column = range.last.column;
+ return;
+ }
+
+ assert(pos.row == range.first.row);
+
+ if (dec_sheet(range, pos))
+ return;
+
+ assert(pos == range.first);
+ throw std::out_of_range("Attempting to decrement beyond the first position.");
+}
+
+using update_func_type = std::function<void(const abs_range_t&,abs_address_t&,bool&)>;
+
+} // anonymous namespace
+
+struct abs_address_iterator::impl
+{
+ const abs_range_t m_range;
+ abs_address_iterator::direction_type m_dir;
+
+ impl(const abs_range_t& range, abs_address_iterator::direction_type dir) :
+ m_range(range), m_dir(dir) {}
+};
+
+struct abs_address_iterator::const_iterator::impl_node
+{
+ const abs_range_t* mp_range;
+ abs_address_t m_pos;
+ bool m_end_pos; //< flag that indicates whether the node is at the position past the last valid address.
+
+ update_func_type m_func_inc;
+ update_func_type m_func_dec;
+
+ impl_node() : mp_range(nullptr), m_pos(abs_address_t::invalid), m_end_pos(false) {}
+
+ impl_node(const abs_range_t& range, abs_address_iterator::direction_type dir, bool end) :
+ mp_range(&range),
+ m_pos(end ? range.last : range.first),
+ m_end_pos(end)
+ {
+ switch (dir)
+ {
+ case abs_address_iterator::direction_type::horizontal:
+ m_func_inc = inc_horizontal;
+ m_func_dec = dec_horizontal;
+ break;
+ case abs_address_iterator::direction_type::vertical:
+ m_func_inc = inc_vertical;
+ m_func_dec = dec_vertical;
+ break;
+ default:
+ throw std::logic_error("unhandled direction value.");
+ }
+ }
+
+ impl_node(const impl_node& r) :
+ mp_range(r.mp_range),
+ m_pos(r.m_pos),
+ m_end_pos(r.m_end_pos),
+ m_func_inc(r.m_func_inc),
+ m_func_dec(r.m_func_dec) {}
+
+ bool equals(const impl_node& r) const
+ {
+ return mp_range == r.mp_range && m_pos == r.m_pos && m_end_pos == r.m_end_pos;
+ }
+
+ void inc()
+ {
+ m_func_inc(*mp_range, m_pos, m_end_pos);
+ }
+
+ void dec()
+ {
+ m_func_dec(*mp_range, m_pos, m_end_pos);
+ }
+};
+
+abs_address_iterator::const_iterator::const_iterator() :
+ mp_impl(ixion::make_unique<impl_node>()) {}
+
+abs_address_iterator::const_iterator::const_iterator(
+ const abs_range_t& range, abs_address_iterator::direction_type dir, bool end) :
+ mp_impl(ixion::make_unique<impl_node>(range, dir, end)) {}
+
+abs_address_iterator::const_iterator::const_iterator(const const_iterator& r) :
+ mp_impl(ixion::make_unique<impl_node>(*r.mp_impl)) {}
+
+abs_address_iterator::const_iterator::const_iterator(const_iterator&& r) :
+ mp_impl(std::move(r.mp_impl)) {}
+
+abs_address_iterator::const_iterator::~const_iterator() {}
+
+abs_address_iterator::const_iterator& abs_address_iterator::const_iterator::operator++()
+{
+ mp_impl->inc();
+ return *this;
+}
+
+abs_address_iterator::const_iterator abs_address_iterator::const_iterator::operator++(int)
+{
+ auto saved = *this;
+ mp_impl->inc();
+ return saved;
+}
+
+abs_address_iterator::const_iterator& abs_address_iterator::const_iterator::operator--()
+{
+ mp_impl->dec();
+ return *this;
+}
+
+abs_address_iterator::const_iterator abs_address_iterator::const_iterator::operator--(int)
+{
+ auto saved = *this;
+ mp_impl->dec();
+ return saved;
+}
+
+const abs_address_iterator::const_iterator::value_type& abs_address_iterator::const_iterator::operator*() const
+{
+ return mp_impl->m_pos;
+}
+
+const abs_address_iterator::const_iterator::value_type* abs_address_iterator::const_iterator::operator->() const
+{
+ return &mp_impl->m_pos;
+}
+
+bool abs_address_iterator::const_iterator::operator== (const const_iterator& r) const
+{
+ return mp_impl->equals(*r.mp_impl);
+}
+
+bool abs_address_iterator::const_iterator::operator!= (const const_iterator& r) const
+{
+ return !operator==(r);
+}
+
+abs_address_iterator::abs_address_iterator(const abs_range_t& range, direction_type dir) :
+ mp_impl(ixion::make_unique<impl>(range, dir)) {}
+
+abs_address_iterator::~abs_address_iterator() {}
+
+abs_address_iterator::const_iterator abs_address_iterator::begin() const
+{
+ return cbegin();
+}
+
+abs_address_iterator::const_iterator abs_address_iterator::end() const
+{
+ return cend();
+}
+
+abs_address_iterator::const_iterator abs_address_iterator::cbegin() const
+{
+ return const_iterator(mp_impl->m_range, mp_impl->m_dir, false);
+}
+
+abs_address_iterator::const_iterator abs_address_iterator::cend() const
+{
+ return const_iterator(mp_impl->m_range, mp_impl->m_dir, true);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/calc_status.cpp b/src/libixion/calc_status.cpp
new file mode 100644
index 0000000..0cc7a03
--- /dev/null
+++ b/src/libixion/calc_status.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "calc_status.hpp"
+
+namespace ixion {
+
+calc_status::calc_status() : result(nullptr), refcount(0) {}
+calc_status::calc_status(const rc_size_t& group_size) :
+ result(nullptr), group_size(group_size), refcount(0) {}
+
+void calc_status::add_ref()
+{
+ ++refcount;
+}
+
+void calc_status::release_ref()
+{
+ if (--refcount == 0)
+ delete this;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/calc_status.hpp b/src/libixion/calc_status.hpp
new file mode 100644
index 0000000..acf14f1
--- /dev/null
+++ b/src/libixion/calc_status.hpp
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_CALC_STATUS_HPP
+#define INCLUDED_IXION_CALC_STATUS_HPP
+
+#include "ixion/formula_result.hpp"
+
+#include <mutex>
+#include <condition_variable>
+
+#include <boost/intrusive_ptr.hpp>
+
+namespace ixion {
+
+struct calc_status
+{
+ calc_status(const calc_status&) = delete;
+ calc_status& operator=(const calc_status&) = delete;
+
+ std::mutex mtx;
+ std::condition_variable cond;
+ std::unique_ptr<formula_result> result;
+
+ const rc_size_t group_size;
+
+ size_t refcount;
+
+ calc_status();
+ calc_status(const rc_size_t& group_size);
+
+ void add_ref();
+ void release_ref();
+};
+
+inline void intrusive_ptr_add_ref(calc_status* p)
+{
+ p->add_ref();
+}
+
+inline void intrusive_ptr_release(calc_status* p)
+{
+ p->release_ref();
+}
+
+using calc_status_ptr_t = boost::intrusive_ptr<calc_status>;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/cell.cpp b/src/libixion/cell.cpp
index 152b922..f0419ab 100644
--- a/src/libixion/cell.cpp
+++ b/src/libixion/cell.cpp
@@ -14,12 +14,10 @@
#include "ixion/interface/formula_model_access.hpp"
#include "ixion/interface/session_handler.hpp"
#include "ixion/global.hpp"
+#include "ixion/matrix.hpp"
#include "formula_interpreter.hpp"
-#include <mutex>
-#include <condition_variable>
-
#include <cassert>
#include <string>
#include <sstream>
@@ -32,6 +30,7 @@
#include "ixion/formula_name_resolver.hpp"
#endif
+#include "calc_status.hpp"
#define FORMULA_CIRCULAR_SAFE 0x01
#define FORMULA_SHARED_TOKENS 0x02
@@ -40,34 +39,23 @@ using namespace std;
namespace ixion {
-struct interpret_status
-{
- interpret_status(const interpret_status&) = delete;
- interpret_status& operator=(const interpret_status&) = delete;
-
- std::mutex mtx;
- std::condition_variable cond;
-
- std::unique_ptr<formula_result> result;
-
- interpret_status() : result(nullptr) {}
-};
-
struct formula_cell::impl
{
- mutable interpret_status m_interpret_status;
- size_t m_identifier;
- bool m_shared_token:1;
+ mutable calc_status_ptr_t m_calc_status;
+ formula_tokens_store_ptr_t m_tokens;
+ rc_address_t m_group_pos;
+
bool m_circular_safe:1;
- impl() :
- m_identifier(0),
- m_shared_token(false),
- m_circular_safe(false) {}
+ impl() : impl(-1, -1, new calc_status, formula_tokens_store_ptr_t()) {}
- impl(size_t tokens_identifier) :
- m_identifier(tokens_identifier),
- m_shared_token(false),
+ impl(const formula_tokens_store_ptr_t& tokens) : impl(-1, -1, new calc_status, tokens) {}
+
+ impl(row_t row, col_t col, const calc_status_ptr_t& cs,
+ const formula_tokens_store_ptr_t& tokens) :
+ m_calc_status(cs),
+ m_tokens(tokens),
+ m_group_pos(row, col, false, false),
m_circular_safe(false) {}
/**
@@ -80,12 +68,12 @@ struct formula_cell::impl
#if DEBUG_FORMULA_CELL
__IXION_DEBUG_OUT__ << "wait for interpreted result" << endl;
#endif
- while (!m_interpret_status.result)
+ while (!m_calc_status->result)
{
#if DEBUG_FORMULA_CELL
__IXION_DEBUG_OUT__ << "waiting" << endl;
#endif
- m_interpret_status.cond.wait(lock);
+ m_calc_status->cond.wait(lock);
}
}
@@ -113,8 +101,8 @@ struct formula_cell::impl
#if DEBUG_FORMULA_CELL
__IXION_DEBUG_OUT__ << "circular dependency detected !!" << endl;
#endif
- assert(!m_interpret_status.result);
- m_interpret_status.result =
+ assert(!m_calc_status->result);
+ m_calc_status->result =
ixion::make_unique<formula_result>(formula_error_t::ref_result_not_available);
return false;
@@ -124,48 +112,136 @@ struct formula_cell::impl
double fetch_value_from_result() const
{
- if (!m_interpret_status.result)
+ if (!m_calc_status->result)
// Result not cached yet. Reference error.
throw formula_error(formula_error_t::ref_result_not_available);
- if (m_interpret_status.result->get_type() == formula_result::result_type::error)
+ if (m_calc_status->result->get_type() == formula_result::result_type::error)
// Error condition.
- throw formula_error(m_interpret_status.result->get_error());
+ throw formula_error(m_calc_status->result->get_error());
+
+ switch (m_calc_status->result->get_type())
+ {
+ case formula_result::result_type::value:
+ return m_calc_status->result->get_value();
+ case formula_result::result_type::matrix:
+ {
+ const matrix& m = m_calc_status->result->get_matrix();
+ row_t row_size = m.row_size();
+ col_t col_size = m.col_size();
- assert(m_interpret_status.result->get_type() == formula_result::result_type::value);
- return m_interpret_status.result->get_value();
+ if (m_group_pos.row >= row_size || m_group_pos.column >= col_size)
+ throw formula_error(formula_error_t::invalid_value_type);
+
+ matrix::element elem = m.get(m_group_pos.row, m_group_pos.column);
+
+ switch (elem.type)
+ {
+ case matrix::element_type::numeric:
+ return elem.numeric;
+ case matrix::element_type::empty:
+ return 0.0;
+ case matrix::element_type::boolean:
+ return elem.boolean ? 1.0 : 0.0;
+ case matrix::element_type::string:
+ default:
+ throw formula_error(formula_error_t::invalid_value_type);
+ }
+ }
+ default:
+ throw formula_error(formula_error_t::invalid_value_type);
+ }
+ }
+
+ bool is_grouped() const
+ {
+ return m_group_pos.column >= 0 && m_group_pos.row >= 0;
+ }
+
+ bool is_group_parent() const
+ {
+ return m_group_pos.column == 0 && m_group_pos.row == 0;
+ }
+
+ bool calc_allowed() const
+ {
+ if (!is_grouped())
+ return true;
+
+ return is_group_parent();
+ }
+
+ formula_result get_single_formula_result(const formula_result& src) const
+ {
+ if (!is_grouped())
+ return src; // returns a copy.
+
+ if (src.get_type() != formula_result::result_type::matrix)
+ // A grouped cell should have a matrix result whose size equals the
+ // size of the group. But in case of anything else, just return the
+ // stored value.
+ return src;
+
+ const matrix& m = src.get_matrix();
+ row_t row_size = m.row_size();
+ col_t col_size = m.col_size();
+
+ if (m_group_pos.row >= row_size || m_group_pos.column >= col_size)
+ return formula_result(formula_error_t::invalid_value_type);
+
+ matrix::element elem = m.get(m_group_pos.row, m_group_pos.column);
+
+ switch (elem.type)
+ {
+ case matrix::element_type::numeric:
+ return formula_result(elem.numeric);
+ case matrix::element_type::string:
+ return formula_result(elem.string_id);
+ case matrix::element_type::empty:
+ return formula_result();
+ case matrix::element_type::boolean:
+ return formula_result(elem.boolean ? 1.0 : 0.0);
+ default:
+ throw std::logic_error("unhandled element type of a matrix result value.");
+ }
}
};
formula_cell::formula_cell() : mp_impl(ixion::make_unique<impl>()) {}
-formula_cell::formula_cell(size_t tokens_identifier) :
- mp_impl(ixion::make_unique<impl>(tokens_identifier)) {}
+formula_cell::formula_cell(const formula_tokens_store_ptr_t& tokens) :
+ mp_impl(ixion::make_unique<impl>(tokens)) {}
+
+formula_cell::formula_cell(
+ row_t group_row, col_t group_col,
+ const calc_status_ptr_t& cs,
+ const formula_tokens_store_ptr_t& tokens) :
+ mp_impl(ixion::make_unique<impl>(group_row, group_col, cs, tokens)) {}
formula_cell::~formula_cell()
{
}
-size_t formula_cell::get_identifier() const
+const formula_tokens_store_ptr_t& formula_cell::get_tokens() const
{
- return mp_impl->m_identifier;
+ return mp_impl->m_tokens;
}
-void formula_cell::set_identifier(size_t identifier)
+void formula_cell::set_tokens(const formula_tokens_store_ptr_t& tokens)
{
- mp_impl->m_identifier = identifier;
+ mp_impl->m_tokens = tokens;
}
double formula_cell::get_value() const
{
- std::unique_lock<std::mutex> lock(mp_impl->m_interpret_status.mtx);
+ std::unique_lock<std::mutex> lock(mp_impl->m_calc_status->mtx);
mp_impl->wait_for_interpreted_result(lock);
return mp_impl->fetch_value_from_result();
}
double formula_cell::get_value_nowait() const
{
- std::lock_guard<std::mutex> lock(mp_impl->m_interpret_status.mtx);
+ std::lock_guard<std::mutex> lock(mp_impl->m_calc_status->mtx);
return mp_impl->fetch_value_from_result();
}
@@ -175,20 +251,25 @@ void formula_cell::interpret(iface::formula_model_access& context, const abs_add
const formula_name_resolver& resolver = context.get_name_resolver();
__IXION_DEBUG_OUT__ << resolver.get_name(pos, false) << ": interpreting" << endl;
#endif
+ if (!mp_impl->calc_allowed())
+ throw std::logic_error("Calculation on this formula cell is not allowed.");
+
+ calc_status& status = *mp_impl->m_calc_status;
+
{
- std::lock_guard<std::mutex> lock(mp_impl->m_interpret_status.mtx);
+ std::lock_guard<std::mutex> lock(status.mtx);
- if (mp_impl->m_interpret_status.result)
+ if (mp_impl->m_calc_status->result)
{
// When the result is already cached before the cell is interpreted,
// it can mean the cell has circular dependency.
- if (mp_impl->m_interpret_status.result->get_type() == formula_result::result_type::error)
+ if (status.result->get_type() == formula_result::result_type::error)
{
auto handler = context.create_session_handler();
if (handler)
{
handler->begin_cell_interpret(pos);
- const char* msg = get_formula_error_name(mp_impl->m_interpret_status.result->get_error());
+ const char* msg = get_formula_error_name(status.result->get_error());
handler->set_formula_error(msg);
handler->end_cell_interpret();
}
@@ -198,50 +279,33 @@ void formula_cell::interpret(iface::formula_model_access& context, const abs_add
formula_interpreter fin(this, context);
fin.set_origin(pos);
- mp_impl->m_interpret_status.result = ixion::make_unique<formula_result>();
+ status.result = ixion::make_unique<formula_result>();
if (fin.interpret())
{
// Successful interpretation.
- *mp_impl->m_interpret_status.result = fin.get_result();
+ *status.result = fin.transfer_result();
}
else
{
// Interpretation ended with an error condition.
- mp_impl->m_interpret_status.result->set_error(fin.get_error());
+ status.result->set_error(fin.get_error());
}
}
- mp_impl->m_interpret_status.cond.notify_all();
+ status.cond.notify_all();
}
void formula_cell::check_circular(const iface::formula_model_access& cxt, const abs_address_t& pos)
{
// TODO: Check to make sure this is being run on the main thread only.
- const formula_tokens_t* tokens = NULL;
- if (is_shared())
- tokens = cxt.get_shared_formula_tokens(pos.sheet, mp_impl->m_identifier);
- else
- tokens = cxt.get_formula_tokens(pos.sheet, mp_impl->m_identifier);
-
- if (!tokens)
- {
- std::ostringstream os;
- if (is_shared())
- os << "failed to retrieve shared formula tokens from formula cell's identifier. ";
- else
- os << "failed to retrieve formula tokens from formula cell's identifier. ";
- os << "(identifier=" << mp_impl->m_identifier << ")";
- throw model_context_error(os.str(), model_context_error::circular_dependency);
- }
-
- formula_tokens_t::const_iterator itr = tokens->begin(), itr_end = tokens->end();
- for (; itr != itr_end; ++itr)
+ const formula_tokens_t& tokens = mp_impl->m_tokens->get();
+ for (const std::unique_ptr<formula_token>& t : tokens)
{
- switch ((*itr)->get_opcode())
+ switch (t->get_opcode())
{
case fop_single_ref:
{
- abs_address_t addr = (*itr)->get_single_ref().to_abs(pos);
+ abs_address_t addr = t->get_single_ref().to_abs(pos);
const formula_cell* ref = cxt.get_formula_cell(addr);
if (!ref)
@@ -249,11 +313,12 @@ void formula_cell::check_circular(const iface::formula_model_access& cxt, const
if (!mp_impl->check_ref_for_circular_safety(*ref, addr))
return;
+
+ break;
}
- break;
case fop_range_ref:
{
- abs_range_t range = (*itr)->get_range_ref().to_abs(pos);
+ abs_range_t range = t->get_range_ref().to_abs(pos);
for (sheet_t sheet = range.first.sheet; sheet <= range.last.sheet; ++sheet)
{
for (col_t col = range.first.column; col <= range.last.column; ++col)
@@ -269,6 +334,8 @@ void formula_cell::check_circular(const iface::formula_model_access& cxt, const
}
}
}
+
+ break;
}
default:
#if DEBUG_FORMULA_CELL
@@ -287,8 +354,8 @@ void formula_cell::check_circular(const iface::formula_model_access& cxt, const
void formula_cell::reset()
{
- std::lock_guard<std::mutex> lock(mp_impl->m_interpret_status.mtx);
- mp_impl->m_interpret_status.result.reset();
+ std::lock_guard<std::mutex> lock(mp_impl->m_calc_status->mtx);
+ mp_impl->m_calc_status->result.reset();
mp_impl->reset_flag();
}
@@ -297,15 +364,6 @@ std::vector<const formula_token*> formula_cell::get_ref_tokens(
{
std::vector<const formula_token*> ret;
- const formula_tokens_t* this_tokens = NULL;
- if (is_shared())
- this_tokens = cxt.get_shared_formula_tokens(pos.sheet, mp_impl->m_identifier);
- else
- this_tokens = cxt.get_formula_tokens(pos.sheet, mp_impl->m_identifier);
-
- if (!this_tokens)
- return ret;
-
std::function<void(const formula_tokens_t::value_type&)> get_refs = [&](const formula_tokens_t::value_type& t)
{
switch (t->get_opcode())
@@ -332,35 +390,59 @@ std::vector<const formula_token*> formula_cell::get_ref_tokens(
}
};
- std::for_each(this_tokens->begin(), this_tokens->end(), get_refs);
+ const formula_tokens_t& this_tokens = mp_impl->m_tokens->get();
+
+ std::for_each(this_tokens.begin(), this_tokens.end(), get_refs);
return ret;
}
-const formula_result& formula_cell::get_result_cache() const
+const formula_result& formula_cell::get_raw_result_cache() const
{
- std::unique_lock<std::mutex> lock(mp_impl->m_interpret_status.mtx);
+ std::unique_lock<std::mutex> lock(mp_impl->m_calc_status->mtx);
mp_impl->wait_for_interpreted_result(lock);
- if (!mp_impl->m_interpret_status.result)
+ if (!mp_impl->m_calc_status->result)
throw formula_error(formula_error_t::ref_result_not_available);
- return *mp_impl->m_interpret_status.result;
+ return *mp_impl->m_calc_status->result;
}
-const formula_result* formula_cell::get_result_cache_nowait() const
+const formula_result* formula_cell::get_raw_result_cache_nowait() const
{
- std::unique_lock<std::mutex> lock(mp_impl->m_interpret_status.mtx);
- return mp_impl->m_interpret_status.result.get();
+ std::unique_lock<std::mutex> lock(mp_impl->m_calc_status->mtx);
+ return mp_impl->m_calc_status->result.get();
}
-bool formula_cell::is_shared() const
+formula_result formula_cell::get_result_cache() const
{
- return mp_impl->m_shared_token;
+ const formula_result& src = get_raw_result_cache();
+ return mp_impl->get_single_formula_result(src);
}
-void formula_cell::set_shared(bool b)
+formula_result formula_cell::get_result_cache_nowait() const
{
- mp_impl->m_shared_token = b;
+ const formula_result* src = get_raw_result_cache_nowait();
+ if (!src)
+ return formula_result(formula_error_t::no_result_error);
+
+ return mp_impl->get_single_formula_result(*src);
+}
+
+formula_group_t formula_cell::get_group_properties() const
+{
+ uintptr_t identity = reinterpret_cast<uintptr_t>(mp_impl->m_calc_status.get());
+ return formula_group_t(mp_impl->m_calc_status->group_size, identity, mp_impl->is_grouped());
+}
+
+abs_address_t formula_cell::get_parent_position(const abs_address_t& pos) const
+{
+ if (!mp_impl->is_grouped())
+ return pos;
+
+ abs_address_t parent_pos = pos;
+ parent_pos.column -= mp_impl->m_group_pos.column;
+ parent_pos.row -= mp_impl->m_group_pos.row;
+ return parent_pos;
}
}
diff --git a/src/libixion/cell_listener_tracker.cpp b/src/libixion/cell_listener_tracker.cpp
index ac482fc..100fc8b 100644
--- a/src/libixion/cell_listener_tracker.cpp
+++ b/src/libixion/cell_listener_tracker.cpp
@@ -7,8 +7,8 @@
#include "ixion/cell_listener_tracker.hpp"
#include "ixion/formula_name_resolver.hpp"
-#include "ixion/interface/formula_model_access.hpp"
#include "ixion/cell.hpp"
+#include "ixion/model_context.hpp"
#include <mdds/rectangle_set.hpp>
@@ -21,6 +21,8 @@
#include <iostream>
#endif
+#include "grouped_ranges.hpp"
+
using namespace std;
namespace ixion {
@@ -33,11 +35,11 @@ typedef std::unordered_map<abs_range_t, cell_listener_tracker::address_set_type*
class dirty_cell_inserter : public std::unary_function<cell_listener_tracker::address_set_type*, void>
{
- iface::formula_model_access& m_context;
+ model_context& m_context;
dirty_formula_cells_t& m_dirty_cells;
cell_listener_tracker::address_set_type& m_addrs;
public:
- dirty_cell_inserter(iface::formula_model_access& cxt, dirty_formula_cells_t& dirty_cells, cell_listener_tracker::address_set_type& addrs) :
+ dirty_cell_inserter(model_context& cxt, dirty_formula_cells_t& dirty_cells, cell_listener_tracker::address_set_type& addrs) :
m_context(cxt), m_dirty_cells(dirty_cells), m_addrs(addrs) {}
void operator() (const cell_listener_tracker::address_set_type* p)
@@ -61,15 +63,17 @@ public:
struct cell_listener_tracker::impl
{
-
- iface::formula_model_access& m_context;
+ model_context& m_context;
mutable range_query_set_type m_query_set; ///< used for fast lookup of range listeners.
cell_store_type m_cell_listeners; ///< store listeners for single cells.
range_store_type m_range_listeners; ///< store listeners for ranges.
cell_listener_tracker::address_set_type m_volatile_cells;
- impl(iface::formula_model_access& cxt) : m_context(cxt) {}
+ grouped_ranges m_grouped_ranges;
+
+ impl(model_context& cxt) :
+ m_context(cxt) {}
~impl()
{
@@ -86,9 +90,6 @@ struct cell_listener_tracker::impl
void cell_listener_tracker::impl::get_all_range_listeners_re(
const abs_address_t& origin_target, const abs_address_t& target, dirty_formula_cells_t& listeners, address_set_type& listeners_addrs) const
{
-#if DEBUG_CELL_LISTENER_TRACKER
- __IXION_DEBUG_OUT__ << "--- begin: target address: " << m_context.get_name_resolver().get_name(target, false) << endl;
-#endif
if (listeners_addrs.count(target))
{
// Target is included in the listener list. No need to scan twice.
@@ -131,16 +132,9 @@ void cell_listener_tracker::impl::get_all_range_listeners_re(
// Add new listeners to the caller's list.
listeners.insert(new_listeners.begin(), new_listeners.end());
listeners_addrs.insert(new_listeners_addrs.begin(), new_listeners_addrs.end());
-#if DEBUG_CELL_LISTENER_TRACKER
- __IXION_DEBUG_OUT__ << "new listeners: ";
- std::for_each(new_listeners_addrs.begin(), new_listeners_addrs.end(),
- cell_addr_printer(m_context.get_name_resolver()));
- cout << endl;
- __IXION_DEBUG_OUT__ << "--- end: target address: " << m_context.get_name_resolver().get_name(target, false) << endl;
-#endif
}
-cell_listener_tracker::cell_listener_tracker(iface::formula_model_access& cxt) :
+cell_listener_tracker::cell_listener_tracker(model_context& cxt) :
mp_impl(make_unique<impl>(cxt)) {}
cell_listener_tracker::~cell_listener_tracker() {}
@@ -148,9 +142,12 @@ cell_listener_tracker::~cell_listener_tracker() {}
void cell_listener_tracker::add(const abs_address_t& src, const abs_address_t& dest)
{
#if DEBUG_CELL_LISTENER_TRACKER
- const formula_name_resolver& res = mp_impl->m_context.get_name_resolver();
- __IXION_DEBUG_OUT__ << "adding - cell src: " << res.get_name(src, false)
- << " cell dest: " << res.get_name(dest, false) << endl;
+ {
+ abs_address_t origin(0,0,0);
+ auto res = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &mp_impl->m_context);
+ __IXION_DEBUG_OUT__ << "adding - cell src: " << res->get_name(src, origin, false)
+ << " cell dest: " << res->get_name(dest, origin, false) << endl;
+ }
#endif
cell_store_type::iterator itr = mp_impl->m_cell_listeners.find(dest);
if (itr == mp_impl->m_cell_listeners.end())
@@ -168,9 +165,12 @@ void cell_listener_tracker::add(const abs_address_t& src, const abs_address_t& d
void cell_listener_tracker::add(const abs_address_t& cell, const abs_range_t& range)
{
#if DEBUG_CELL_LISTENER_TRACKER
- const formula_name_resolver& res = mp_impl->m_context.get_name_resolver();
- __IXION_DEBUG_OUT__ << "adding - cell: " << res.get_name(cell, false)
- << " range: " << res.get_name(range, false) << endl;
+ {
+ abs_address_t origin(0,0,0);
+ auto res = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &mp_impl->m_context);
+ __IXION_DEBUG_OUT__ << "adding - cell src: " << res->get_name(cell, origin, false)
+ << " range dest: " << res->get_name(range, origin, false) << endl;
+ }
#endif
range_store_type::iterator itr = mp_impl->m_range_listeners.find(range);
if (itr == mp_impl->m_range_listeners.end())
@@ -212,10 +212,6 @@ void cell_listener_tracker::remove(const abs_address_t& src, const abs_address_t
void cell_listener_tracker::remove(const abs_address_t& cell, const abs_range_t& range)
{
-#if DEBUG_CELL_LISTENER_TRACKER
- const formula_name_resolver& res = mp_impl->m_context.get_name_resolver();
- __IXION_DEBUG_OUT__ << "removing - cell: " << res.get_name(cell, false) << " range: " << res.get_name(range, false) << endl;
-#endif
range_store_type::iterator itr = mp_impl->m_range_listeners.find(range);
if (itr == mp_impl->m_range_listeners.end())
// No listeners for this range. Bail out.
@@ -267,10 +263,6 @@ public:
void cell_listener_tracker::get_all_cell_listeners(
const abs_address_t& target, dirty_formula_cells_t& listeners) const
{
-#if DEBUG_CELL_LISTENER_TRACKER
- const formula_name_resolver& res = mp_impl->m_context.get_name_resolver();
- __IXION_DEBUG_OUT__ << "target cell: " << res.get_name(target, false) << endl;
-#endif
cell_store_type::const_iterator itr = mp_impl->m_cell_listeners.find(target);
if (itr == mp_impl->m_cell_listeners.end())
// This target cell has no listeners.
@@ -298,39 +290,27 @@ void cell_listener_tracker::get_all_cell_listeners(
void cell_listener_tracker::get_all_range_listeners(
const abs_address_t& target, dirty_formula_cells_t& listeners) const
{
-#if DEBUG_CELL_LISTENER_TRACKER
- __IXION_DEBUG_OUT__ << get_formula_result_output_separator() << endl;
- __IXION_DEBUG_OUT__ << "get all range listeners for target " << mp_impl->m_context.get_name_resolver().get_name(target, false) << endl;
-#endif
-
address_set_type listeners_addrs; // to keep track of circular references.
mp_impl->get_all_range_listeners_re(target, target, listeners, listeners_addrs);
}
-void cell_listener_tracker::print_cell_listeners(
- const abs_address_t& target, const formula_name_resolver& resolver) const
+void cell_listener_tracker::add_grouped_range(
+ sheet_t sheet, const abs_rc_range_t& range, uintptr_t identity)
{
- {
- address_t pos_display(target);
- pos_display.set_absolute(false);
- cout << "The following cells listen to cell "
- << resolver.get_name(pos_display, abs_address_t(), false) << endl;
- }
+ mp_impl->m_grouped_ranges.add(sheet, range, identity);
+}
- cell_store_type::const_iterator itr = mp_impl->m_cell_listeners.find(target);
- if (itr == mp_impl->m_cell_listeners.end())
- // No one listens to this target.
- return;
+void cell_listener_tracker::remove_grouped_range(sheet_t sheet, uintptr_t identity)
+{
+ return mp_impl->m_grouped_ranges.remove(sheet, identity);
+}
- const address_set_type& addrs = *itr->second;
- address_set_type::const_iterator itr2 = addrs.begin(), itr2_end = addrs.end();
- for (; itr2 != itr2_end; ++itr2)
- {
- address_t pos_display(*itr2);
- pos_display.set_absolute(false);
- cout << " cell " << resolver.get_name(pos_display, abs_address_t(), false) << endl;
- }
+abs_rc_address_t cell_listener_tracker::move_to_grouped_range_origin(
+ sheet_t sheet, const abs_rc_address_t& pos) const
+{
+ return mp_impl->m_grouped_ranges.move_to_origin(sheet, pos);
}
}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/compute_engine.cpp b/src/libixion/compute_engine.cpp
new file mode 100644
index 0000000..4df65bd
--- /dev/null
+++ b/src/libixion/compute_engine.cpp
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ixion/compute_engine.hpp"
+#include "ixion/global.hpp"
+
+#include <iostream>
+#include <unordered_map>
+
+namespace ixion { namespace draft {
+
+namespace {
+
+struct class_factory
+{
+ create_compute_engine_t create;
+ destroy_compute_engine_t destroy;
+};
+
+using class_factory_store_t = std::unordered_map<std::string, class_factory>;
+
+class_factory_store_t class_factory_store;
+
+}
+
+struct compute_engine::impl
+{
+ impl() {}
+};
+
+std::shared_ptr<compute_engine> compute_engine::create(const char* name)
+{
+ if (!name)
+ // Name is not specified. Use the default engine.
+ return std::make_shared<compute_engine>();
+
+ class_factory_store_t::iterator it = class_factory_store.find(name);
+ if (it == class_factory_store.end())
+ // No class factory for this name. Fall back to default.
+ return std::make_shared<compute_engine>();
+
+ const class_factory& cf = it->second;
+ return std::shared_ptr<compute_engine>(cf.create(), cf.destroy);
+}
+
+void compute_engine::add_class(
+ const char* name, create_compute_engine_t func_create, destroy_compute_engine_t func_destroy)
+{
+ class_factory cf;
+ cf.create = func_create;
+ cf.destroy = func_destroy;
+
+ class_factory_store.emplace(name, cf);
+}
+
+compute_engine::compute_engine() :
+ mp_impl(ixion::make_unique<impl>())
+{
+}
+
+compute_engine::~compute_engine()
+{
+}
+
+const char* compute_engine::get_name() const
+{
+ return "default";
+}
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/compute_engine_cuda.cpp b/src/libixion/compute_engine_cuda.cpp
new file mode 100644
index 0000000..bfc55e7
--- /dev/null
+++ b/src/libixion/compute_engine_cuda.cpp
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "compute_engine_cuda.hpp"
+#include "ixion/module.hpp"
+#include "ixion/env.hpp"
+#include <iostream>
+
+namespace ixion { namespace draft {
+
+compute_engine_cuda::compute_engine_cuda() : compute_engine()
+{
+ std::cout << __FILE__ << ":" << __LINE__ << " (compute_engine_cuda:compute_engine_cuda): ctor" << std::endl;
+}
+
+compute_engine_cuda::~compute_engine_cuda()
+{
+ std::cout << __FILE__ << ":" << __LINE__ << " (compute_engine_cuda:~compute_engine_cuda): dtor" << std::endl;
+}
+
+const char* compute_engine_cuda::get_name() const
+{
+ return "cuda";
+}
+
+compute_engine* create()
+{
+ return new compute_engine_cuda();
+}
+
+void destroy(const compute_engine* p)
+{
+ delete static_cast<const compute_engine_cuda*>(p);
+}
+
+}}
+
+extern "C" {
+
+IXION_DLLPUBLIC ixion::draft::module_def* register_module()
+{
+ static ixion::draft::module_def md =
+ {
+ ixion::draft::create,
+ ixion::draft::destroy
+ };
+
+ return &md;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/compute_engine_cuda.hpp b/src/libixion/compute_engine_cuda.hpp
new file mode 100644
index 0000000..44a08ad
--- /dev/null
+++ b/src/libixion/compute_engine_cuda.hpp
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_COMPUTE_ENGINE_CUDA_HPP
+#define INCLUDED_IXION_COMPUTE_ENGINE_CUDA_HPP
+
+#include "ixion/compute_engine.hpp"
+
+namespace ixion { namespace draft {
+
+class compute_engine_cuda : public compute_engine
+{
+public:
+ compute_engine_cuda();
+ virtual ~compute_engine_cuda();
+
+ virtual const char* get_name() const override;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/compute_engine_test.cpp b/src/libixion/compute_engine_test.cpp
new file mode 100644
index 0000000..08dd658
--- /dev/null
+++ b/src/libixion/compute_engine_test.cpp
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <ixion/compute_engine.hpp>
+#include <ixion/module.hpp>
+#include <iostream>
+#include <cassert>
+#include <cstring>
+
+void test_create_default()
+{
+ std::shared_ptr<ixion::draft::compute_engine> p = ixion::draft::compute_engine::create(nullptr);
+ assert(p);
+ assert(!std::strcmp(p->get_name(), "default"));
+}
+
+void test_create_cuda()
+{
+ std::shared_ptr<ixion::draft::compute_engine> p = ixion::draft::compute_engine::create("cuda");
+ assert(p);
+ assert(!std::strcmp(p->get_name(), "cuda"));
+}
+
+int main()
+{
+ ixion::draft::init_modules();
+
+ test_create_default();
+#ifdef BUILD_CUDA
+ test_create_cuda();
+#endif
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/config.cpp b/src/libixion/config.cpp
index adbd15e..eb1de0b 100644
--- a/src/libixion/config.cpp
+++ b/src/libixion/config.cpp
@@ -10,10 +10,17 @@
namespace ixion {
config::config() :
- sep_function_arg(',') {}
+ sep_function_arg(','),
+ sep_matrix_column(','),
+ sep_matrix_row(';'),
+ output_precision(-1) {}
config::config(const config& r) :
- sep_function_arg(r.sep_function_arg) {}
+ sep_function_arg(r.sep_function_arg),
+ sep_matrix_column(r.sep_matrix_column),
+ sep_matrix_row(r.sep_matrix_row),
+ output_precision(r.output_precision) {}
}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/constants.inl.in b/src/libixion/constants.inl.in
index b6ae691..90fca83 100644
--- a/src/libixion/constants.inl.in
+++ b/src/libixion/constants.inl.in
@@ -2,3 +2,6 @@
#define IXION_MAJOR_VERSION @IXION_MAJOR_VERSION@
#define IXION_MINOR_VERSION @IXION_MINOR_VERSION@
#define IXION_MICRO_VERSION @IXION_MICRO_VERSION@
+#define IXION_MAJOR_API_VERSION @IXION_MAJOR_API_VERSION@
+#define IXION_MINOR_API_VERSION @IXION_MINOR_API_VERSION@
+
diff --git a/src/libixion/formula.cpp b/src/libixion/formula.cpp
index e02640a..cc26894 100644
--- a/src/libixion/formula.cpp
+++ b/src/libixion/formula.cpp
@@ -35,7 +35,7 @@ formula_tokens_t parse_formula_string(
const formula_name_resolver& resolver, const char* p, size_t n)
{
lexer_tokens_t lxr_tokens;
- formula_lexer lexer(p, n);
+ formula_lexer lexer(cxt.get_config(), p, n);
lexer.tokenize();
lexer.swap_tokens(lxr_tokens);
@@ -91,7 +91,7 @@ public:
m_os << token->get_value();
break;
case fop_sep:
- m_os << ",";
+ m_os << m_cxt.get_config().sep_function_arg;
break;
case fop_function:
{
@@ -193,15 +193,35 @@ void register_formula_cell(iface::formula_model_access& cxt, const abs_address_t
// Not a formula cell. Bail out.
return;
+ cell_listener_tracker& tracker = cxt.get_cell_listener_tracker();
+
std::vector<const formula_token*> ref_tokens = cell->get_ref_tokens(cxt, pos);
- std::for_each(ref_tokens.begin(), ref_tokens.end(),
- formula_cell_listener_handler(cxt,
- pos, formula_cell_listener_handler::mode_add));
+
+ for (const formula_token* p : ref_tokens)
+ {
+ switch (p->get_opcode())
+ {
+ case fop_single_ref:
+ {
+ abs_address_t addr = p->get_single_ref().to_abs(pos);
+ tracker.add(pos, addr);
+ break;
+ }
+ case fop_range_ref:
+ {
+ abs_range_t range = p->get_range_ref().to_abs(pos);
+ tracker.add(pos, range);
+ break;
+ }
+ default:
+ ; // ignore the rest.
+ }
+ }
// Check if the cell is volatile.
- const formula_tokens_t* tokens = cxt.get_formula_tokens(pos.sheet, cell->get_identifier());
- if (tokens && has_volatile(*tokens))
- cxt.get_cell_listener_tracker().add_volatile(pos);
+ const formula_tokens_store_ptr_t& ts = cell->get_tokens();
+ if (ts && has_volatile(ts->get()))
+ tracker.add_volatile(pos);
}
void unregister_formula_cell(iface::formula_model_access& cxt, const abs_address_t& pos)
@@ -220,9 +240,28 @@ void unregister_formula_cell(iface::formula_model_access& cxt, const abs_address
// itself as their listener. This step is important
// especially during partial re-calculation.
std::vector<const formula_token*> ref_tokens = fcell->get_ref_tokens(cxt, pos);
- for_each(ref_tokens.begin(), ref_tokens.end(),
- formula_cell_listener_handler(cxt,
- pos, formula_cell_listener_handler::mode_remove));
+
+ for (const formula_token* p : ref_tokens)
+ {
+
+ switch (p->get_opcode())
+ {
+ case fop_single_ref:
+ {
+ abs_address_t addr = p->get_single_ref().to_abs(pos);
+ tracker.remove(pos, addr);
+ break;
+ }
+ case fop_range_ref:
+ {
+ abs_range_t range = p->get_range_ref().to_abs(pos);
+ tracker.remove(pos, range);
+ break;
+ }
+ default:
+ ; // ignore the rest.
+ }
+ }
}
void get_all_dirty_cells(
@@ -248,18 +287,26 @@ void get_all_dirty_cells(
}
}
+ // Get all range listeners first, then add the listeners to the list of
+ // modified cells, to get their listeners too.
+
+ dirty_formula_cells_t range_listeners;
+ for (const abs_address_t& addr : addrs)
+ tracker.get_all_range_listeners(addr, range_listeners);
+
+ for (const abs_address_t& cell : range_listeners)
+ {
+ addrs.push_back(cell);
+ cells.insert(cell);
+ }
+
// Remove duplicate entries.
std::sort(addrs.begin(), addrs.end());
addrs.erase(std::unique(addrs.begin(), addrs.end()), addrs.end());
- {
- modified_cells_t::const_iterator itr = addrs.begin(), itr_end = addrs.end();
- for (; itr != itr_end; ++itr)
- {
- tracker.get_all_range_listeners(*itr, cells);
- tracker.get_all_cell_listeners(*itr, cells);
- }
- }
+ // Now get the single cell listeners.
+ for (const abs_address_t& addr : addrs)
+ tracker.get_all_cell_listeners(addr, cells);
}
void calculate_cells(iface::formula_model_access& cxt, dirty_formula_cells_t& cells, size_t thread_count)
diff --git a/src/libixion/formula_functions.cpp b/src/libixion/formula_functions.cpp
index 35df5ac..95a8501 100644
--- a/src/libixion/formula_functions.cpp
+++ b/src/libixion/formula_functions.cpp
@@ -11,6 +11,7 @@
#include "ixion/matrix.hpp"
#include "ixion/mem_str_buf.hpp"
#include "ixion/interface/formula_model_access.hpp"
+#include "ixion/macros.hpp"
#ifdef max
#undef max
@@ -27,33 +28,43 @@
#include <thread>
#include <chrono>
+#include <mdds/sorted_string_map.hpp>
+
using namespace std;
namespace ixion {
namespace {
-struct builtin_func
+namespace builtin_funcs {
+
+typedef mdds::sorted_string_map<formula_function_t> map_type;
+
+// Keys must be sorted.
+const std::vector<map_type::entry> entries =
{
- const char* name;
- formula_function_t oc;
+ { IXION_ASCII("AVERAGE"), formula_function_t::func_average },
+ { IXION_ASCII("CONCATENATE"), formula_function_t::func_concatenate },
+ { IXION_ASCII("COUNTA"), formula_function_t::func_counta },
+ { IXION_ASCII("IF"), formula_function_t::func_if },
+ { IXION_ASCII("LEN"), formula_function_t::func_len },
+ { IXION_ASCII("MAX"), formula_function_t::func_max },
+ { IXION_ASCII("MIN"), formula_function_t::func_min },
+ { IXION_ASCII("MMULT"), formula_function_t::func_mmult },
+ { IXION_ASCII("NOW"), formula_function_t::func_now },
+ { IXION_ASCII("SUBTOTAL"), formula_function_t::func_subtotal },
+ { IXION_ASCII("SUM"), formula_function_t::func_sum },
+ { IXION_ASCII("WAIT"), formula_function_t::func_wait },
};
-const builtin_func builtin_funcs[] = {
- { "MAX", formula_function_t::func_max },
- { "MIN", formula_function_t::func_min },
- { "AVERAGE", formula_function_t::func_average },
- { "WAIT", formula_function_t::func_wait },
- { "SUM", formula_function_t::func_sum },
- { "COUNTA", formula_function_t::func_counta },
- { "IF", formula_function_t::func_if },
- { "LEN", formula_function_t::func_len },
- { "CONCATENATE", formula_function_t::func_concatenate },
- { "NOW", formula_function_t::func_now },
- { "SUBTOTAL", formula_function_t::func_subtotal },
-};
+const map_type& get()
+{
+ static map_type mt(entries.data(), entries.size(), formula_function_t::func_unknown);
+ return mt;
+}
-size_t builtin_func_count = sizeof(builtin_funcs) / sizeof(builtin_func);
+
+} // anonymous namespace
const char* unknown_func_name = "unknown";
@@ -72,36 +83,34 @@ double sum_matrix_elements(const matrix& mx)
return sum;
}
-/**
- * Compare given string with a known function name to see if they are equal.
- * The comparison is case-insensitive.
- *
- * @param func_name function name. Null-terminated, and is all in upper
- * case.
- * @param p string to test. Not null-terminated and may be in mixed case.
- * @param n length of the string being tested.
- *
- * @return true if they are equal, false otherwise.
- */
-bool match_func_name(const char* func_name, const char* p, size_t n)
+numeric_matrix multiply_matrices(const matrix& left, const matrix& right)
{
- const char* fp = func_name;
- for (size_t i = 0; i < n; ++i, ++p, ++fp)
- {
- if (!*fp)
- // function name ended first.
- return false;
+ // The column size of the left matrix must equal the row size of the right
+ // matrix.
- char c = *p;
- if (c > 'Z')
- // convert to upper case.
- c -= 'a' - 'A';
+ size_t n = left.col_size();
+
+ if (n != right.row_size())
+ throw formula_error(formula_error_t::invalid_expression);
+
+ numeric_matrix left_nm = left.as_numeric();
+ numeric_matrix right_nm = right.as_numeric();
- if (c != *fp)
- return false;
+ numeric_matrix output(left_nm.row_size(), right_nm.col_size());
+
+ for (size_t row = 0; row < output.row_size(); ++row)
+ {
+ for (size_t col = 0; col < output.col_size(); ++col)
+ {
+ double v = 0.0;
+ for (size_t i = 0; i < n; ++i)
+ v += left_nm(row, i) * right_nm(i, col);
+
+ output(row, col) = v;
+ }
}
- return *fp == 0;
+ return output;
}
}
@@ -119,20 +128,30 @@ formula_function_t formula_functions::get_function_opcode(const formula_token& t
formula_function_t formula_functions::get_function_opcode(const char* p, size_t n)
{
- for (size_t i = 0; i < builtin_func_count; ++i)
+ std::string upper;
+
+ for (const char* p_end = p + n; p != p_end; ++p)
{
- if (match_func_name(builtin_funcs[i].name, p, n))
- return builtin_funcs[i].oc;
+ char c = *p;
+
+ if (c > 'Z')
+ {
+ // Convert to upper case.
+ c -= 'a' - 'A';
+ }
+
+ upper.push_back(c);
}
- return formula_function_t::func_unknown;
+
+ return builtin_funcs::get().find(upper.data(), upper.size());
}
const char* formula_functions::get_function_name(formula_function_t oc)
{
- for (size_t i = 0; i < builtin_func_count; ++i)
+ for (const builtin_funcs::map_type::entry& e : builtin_funcs::entries)
{
- if (oc == builtin_funcs[i].oc)
- return builtin_funcs[i].name;
+ if (e.value == oc)
+ return e.key;
}
return unknown_func_name;
}
@@ -183,6 +202,9 @@ void formula_functions::interpret(formula_function_t oc, value_stack_t& args)
case formula_function_t::func_subtotal:
fnc_subtotal(args);
break;
+ case formula_function_t::func_mmult:
+ fnc_mmult(args);
+ break;
case formula_function_t::func_unknown:
default:
throw formula_functions::invalid_arg("unknown function opcode");
@@ -330,6 +352,59 @@ void formula_functions::fnc_average(value_stack_t& args) const
args.push_value(ret/count);
}
+void formula_functions::fnc_mmult(value_stack_t& args) const
+{
+ matrix mx[2];
+ matrix* mxp = mx;
+ const matrix* mxp_end = mxp + 2;
+
+ bool invalid_arg = false;
+
+ // NB : the stack is LIFO i.e. the first matrix is the right matrix and
+ // the second one is the left one.
+
+ while (!args.empty())
+ {
+ switch (args.get_type())
+ {
+ case stack_value_t::range_ref:
+ {
+ if (mxp == mxp_end)
+ {
+ invalid_arg = true;
+ break;
+ }
+
+ matrix m = args.pop_range_value();
+ mxp->swap(m);
+ ++mxp;
+ break;
+ }
+ default:
+ invalid_arg = true;
+ }
+
+ if (invalid_arg)
+ break;
+ }
+
+ if (mxp != mxp_end)
+ invalid_arg = true;
+
+ if (invalid_arg)
+ throw formula_functions::invalid_arg("MMULT requires exactly two ranges.");
+
+ mx[0].swap(mx[1]); // Make it so that 0 -> left and 1 -> right.
+
+ if (!mx[0].is_numeric() || !mx[1].is_numeric())
+ throw formula_functions::invalid_arg(
+ "MMULT requires two numeric ranges. At least one range is not numeric.");
+
+ numeric_matrix ans = multiply_matrices(mx[0], mx[1]);
+
+ args.push_matrix(ans);
+}
+
void formula_functions::fnc_if(value_stack_t& args) const
{
if (args.size() != 3)
diff --git a/src/libixion/formula_functions.hpp b/src/libixion/formula_functions.hpp
index dc4c6bf..3df048e 100644
--- a/src/libixion/formula_functions.hpp
+++ b/src/libixion/formula_functions.hpp
@@ -57,6 +57,7 @@ private:
void fnc_sum(value_stack_t& args) const;
void fnc_counta(value_stack_t& args) const;
void fnc_average(value_stack_t& args) const;
+ void fnc_mmult(value_stack_t& args) const;
void fnc_if(value_stack_t& args) const;
diff --git a/src/libixion/formula_interpreter.cpp b/src/libixion/formula_interpreter.cpp
index 33c7a76..3b9d224 100644
--- a/src/libixion/formula_interpreter.cpp
+++ b/src/libixion/formula_interpreter.cpp
@@ -12,6 +12,7 @@
#include "ixion/cell.hpp"
#include "ixion/global.hpp"
#include "ixion/formula_name_resolver.hpp"
+#include "ixion/matrix.hpp"
#include "ixion/interface/formula_model_access.hpp"
#include "ixion/interface/session_handler.hpp"
#include "ixion/interface/table_handler.hpp"
@@ -106,7 +107,7 @@ bool formula_interpreter::interpret()
catch (const formula_error& e)
{
#if DEBUG_FORMULA_INTERPRETER
- __IXION_DEBUG_OUT__ << "formula error" << endl;
+ __IXION_DEBUG_OUT__ << "formula error: " << e.what() << endl;
#endif
if (mp_handler)
mp_handler->set_formula_error(e.what());
@@ -120,9 +121,9 @@ bool formula_interpreter::interpret()
return false;
}
-const formula_result& formula_interpreter::get_result() const
+formula_result formula_interpreter::transfer_result()
{
- return m_result;
+ return std::move(m_result);
}
formula_error_t formula_interpreter::get_error() const
@@ -135,20 +136,15 @@ void formula_interpreter::init_tokens()
name_set used_names;
m_tokens.clear();
m_stack.clear();
- const formula_tokens_t* orig_tokens = NULL;
- if (m_parent_cell->is_shared())
- orig_tokens = m_context.get_shared_formula_tokens(m_pos.sheet, m_parent_cell->get_identifier());
- else
- orig_tokens = m_context.get_formula_tokens(m_pos.sheet, m_parent_cell->get_identifier());
- if (!orig_tokens)
+ const formula_tokens_store_ptr_t& ts = m_parent_cell->get_tokens();
+ if (!ts)
return;
- formula_tokens_t::const_iterator itr = orig_tokens->begin(), itr_end = orig_tokens->end();
- for (; itr != itr_end; ++itr)
+ const formula_tokens_t& src_tokens = ts->get();
+
+ for (const std::unique_ptr<formula_token>& p : src_tokens)
{
- const formula_token* p = &(**itr);
- assert(p);
if (p->get_opcode() == fop_named_expression)
{
// Named expression. Expand it.
@@ -159,8 +155,9 @@ void formula_interpreter::init_tokens()
}
else
// Normal token.
- m_tokens.push_back(p);
+ m_tokens.push_back(p.get());
}
+
m_end_token_pos = m_tokens.end();
}
@@ -201,29 +198,32 @@ void formula_interpreter::pop_result()
{
// there should only be one stack value left for the result value.
assert(m_stack.size() == 1);
- const stack_value& res = m_stack.back();
+ stack_value& res = m_stack.back();
switch (res.get_type())
{
case stack_value_t::range_ref:
{
const abs_range_t& range = res.get_range();
get_result_from_cell(m_context, range.first, m_result);
+ break;
}
- break;
case stack_value_t::single_ref:
{
get_result_from_cell(m_context, res.get_address(), m_result);
+ break;
}
- break;
case stack_value_t::string:
m_result.set_string(res.get_string());
- break;
+ break;
case stack_value_t::value:
#if DEBUG_FORMULA_INTERPRETER
__IXION_DEBUG_OUT__ << "result: " << res.get_value() << endl;
#endif
m_result.set_value(res.get_value());
- break;
+ break;
+ case stack_value_t::matrix:
+ m_result.set_matrix(res.pop_matrix());
+ break;
default:
;
}
@@ -356,7 +356,7 @@ bool pop_stack_value_or_string(const iface::formula_model_access& cxt,
{
const formula_cell* fc = cxt.get_formula_cell(addr);
assert(fc);
- const formula_result& res = fc->get_result_cache();
+ formula_result res = fc->get_result_cache();
switch (res.get_type())
{
diff --git a/src/libixion/formula_interpreter.hpp b/src/libixion/formula_interpreter.hpp
index 81771e0..01100c9 100644
--- a/src/libixion/formula_interpreter.hpp
+++ b/src/libixion/formula_interpreter.hpp
@@ -57,7 +57,7 @@ public:
void set_origin(const abs_address_t& pos);
bool interpret();
- const formula_result& get_result() const;
+ formula_result transfer_result();
formula_error_t get_error() const;
private:
diff --git a/src/libixion/formula_lexer.cpp b/src/libixion/formula_lexer.cpp
index a9aeb9c..b43b2c3 100644
--- a/src/libixion/formula_lexer.cpp
+++ b/src/libixion/formula_lexer.cpp
@@ -46,6 +46,8 @@ public:
void run();
+ void set_sep_arg(char c);
+
private:
bool is_arg_sep(char c) const;
bool is_decimal_sep(char c) const;
@@ -154,6 +156,11 @@ void tokenizer::run()
}
}
+void tokenizer::set_sep_arg(char c)
+{
+ m_sep_arg = c;
+}
+
bool tokenizer::is_arg_sep(char c) const
{
return c == m_sep_arg;
@@ -321,8 +328,8 @@ bool tokenizer::has_char() const
formula_lexer::tokenize_error::tokenize_error(const string& msg) : general_error(msg) {}
-formula_lexer::formula_lexer(const char* p, size_t n) :
- mp_first(p), m_size(n) {}
+formula_lexer::formula_lexer(const config& config, const char* p, size_t n) :
+ m_config(config), mp_first(p), m_size(n) {}
formula_lexer::~formula_lexer() {}
@@ -332,6 +339,7 @@ void formula_lexer::tokenize()
__IXION_DEBUG_OUT__ << "formula string: '" << std::string(mp_first, m_size) << "'" << endl;
#endif
tokenizer tkr(m_tokens, mp_first, m_size);
+ tkr.set_sep_arg(m_config.sep_function_arg);
tkr.run();
#if IXION_DEBUG_LEXER
__IXION_DEBUG_OUT__ << print_tokens(m_tokens, true) << endl;
diff --git a/src/libixion/formula_lexer.hpp b/src/libixion/formula_lexer.hpp
index 2d9dc39..545e031 100644
--- a/src/libixion/formula_lexer.hpp
+++ b/src/libixion/formula_lexer.hpp
@@ -13,6 +13,7 @@
#include "ixion/mem_str_buf.hpp"
#include "ixion/exceptions.hpp"
+#include "ixion/config.hpp"
#include "lexer_tokens.hpp"
@@ -30,7 +31,7 @@ public:
tokenize_error(const std::string& msg);
};
- formula_lexer(const char* p, size_t n);
+ formula_lexer(const config& config, const char* p, size_t n);
~formula_lexer();
void tokenize();
@@ -43,6 +44,7 @@ public:
void swap_tokens(lexer_tokens_t& tokens);
private:
+ const config& m_config;
lexer_tokens_t m_tokens;
const char* mp_first;
size_t m_size;
diff --git a/src/libixion/formula_name_resolver.cpp b/src/libixion/formula_name_resolver.cpp
index 1b9007c..cf4a2ce 100644
--- a/src/libixion/formula_name_resolver.cpp
+++ b/src/libixion/formula_name_resolver.cpp
@@ -29,7 +29,7 @@ namespace {
bool check_address_by_sheet_bounds(const iface::formula_model_access* cxt, const address_t& pos)
{
- sheet_size_t ss(row_upper_bound, column_upper_bound);
+ rc_size_t ss(row_upper_bound, column_upper_bound);
if (cxt && pos.sheet >= 0 && size_t(pos.sheet) < cxt->get_sheet_count())
{
diff --git a/src/libixion/formula_result.cpp b/src/libixion/formula_result.cpp
index a80fc8e..f3e143b 100644
--- a/src/libixion/formula_result.cpp
+++ b/src/libixion/formula_result.cpp
@@ -9,9 +9,12 @@
#include "ixion/mem_str_buf.hpp"
#include "ixion/exceptions.hpp"
#include "ixion/interface/formula_model_access.hpp"
+#include "ixion/config.hpp"
+#include "ixion/matrix.hpp"
#include <cassert>
#include <sstream>
+#include <iomanip>
#define DEBUG_FORMULA_RESULT 0
@@ -26,10 +29,13 @@ namespace ixion {
struct formula_result::impl
{
result_type m_type;
- union {
+
+ union
+ {
string_id_t m_str_identifier;
double m_value;
formula_error_t m_error;
+ matrix* m_matrix;
};
impl() : m_type(result_type::value), m_value(0.0) {}
@@ -43,42 +49,72 @@ struct formula_result::impl
{
case result_type::value:
m_value = other.m_value;
- break;
+ break;
case result_type::string:
m_str_identifier = other.m_str_identifier;
- break;
+ break;
case result_type::error:
m_error = other.m_error;
- break;
+ break;
+ case result_type::matrix:
+ m_matrix = new matrix(*other.m_matrix);
+ break;
default:
assert(!"unknown formula result type specified during copy construction.");
}
}
+ ~impl()
+ {
+ clear_matrix();
+ }
+
+ void clear_matrix()
+ {
+ if (m_type == result_type::matrix)
+ delete m_matrix;
+ }
+
void reset()
{
+ clear_matrix();
m_type = result_type::value;
m_value = 0.0;
}
void set_value(double v)
{
+ clear_matrix();
m_type = result_type::value;
m_value = v;
}
void set_string(string_id_t strid)
{
+ clear_matrix();
m_type = result_type::string;
m_str_identifier = strid;
}
void set_error(formula_error_t e)
{
+ clear_matrix();
m_type = result_type::error;
m_error = e;
}
+ void set_matrix(matrix mtx)
+ {
+ if (m_type == result_type::matrix)
+ {
+ *m_matrix = std::move(mtx);
+ return;
+ }
+
+ m_type = result_type::matrix;
+ m_matrix = new matrix(std::move(mtx));
+ }
+
double get_value() const
{
assert(m_type == result_type::value);
@@ -97,6 +133,12 @@ struct formula_result::impl
return m_error;
}
+ const matrix& get_matrix() const
+ {
+ assert(m_type == result_type::matrix);
+ return *m_matrix;
+ }
+
result_type get_type() const
{
return m_type;
@@ -116,9 +158,64 @@ struct formula_result::impl
case result_type::value:
{
ostringstream os;
+ if (cxt.get_config().output_precision >= 0)
+ os << std::fixed << std::setprecision(cxt.get_config().output_precision);
os << m_value;
return os.str();
}
+ case result_type::matrix:
+ {
+ const matrix& m = *m_matrix;
+
+ std::ostringstream os;
+
+ os << '{';
+
+ for (size_t row = 0; row < m.row_size(); ++row)
+ {
+ if (row > 0)
+ os << cxt.get_config().sep_matrix_row;
+
+ for (size_t col = 0; col < m.col_size(); ++col)
+ {
+ if (col > 0)
+ os << cxt.get_config().sep_matrix_column;
+
+ matrix::element e = m.get(row, col);
+
+ switch (e.type)
+ {
+ case matrix::element_type::numeric:
+ {
+ os << e.numeric;
+ break;
+ }
+ case matrix::element_type::string:
+ {
+ const std::string* p = cxt.get_string(e.string_id);
+
+ if (p)
+ os << '"' << *p << '"';
+ else
+ os << "\"#ERR!\"";
+
+ break;
+ }
+ case matrix::element_type::boolean:
+ {
+ os << e.boolean;
+ break;
+ }
+ default:
+ ;
+ }
+ }
+ }
+
+ os << '}';
+
+ return os.str();
+ }
default:
assert(!"unknown formula result type!");
}
@@ -146,6 +243,7 @@ struct formula_result::impl
case 'f':
{
// parse this as a boolean value.
+ clear_matrix();
m_value = global::to_bool(p, n) ? 1.0 : 0.0;
m_type = result_type::value;
break;
@@ -153,26 +251,33 @@ struct formula_result::impl
default:
{
// parse this as a number.
+ clear_matrix();
m_value = global::to_double(p, n);
m_type = result_type::value;
}
}
}
- void assign_from(const formula_result& r)
+ void move_from(formula_result&& r)
{
+ clear_matrix();
m_type = r.mp_impl->m_type;
+
switch (m_type)
{
case result_type::value:
m_value = r.mp_impl->m_value;
- break;
+ break;
case result_type::string:
m_str_identifier = r.mp_impl->m_str_identifier;
- break;
+ break;
case result_type::error:
m_error = r.mp_impl->m_error;
- break;
+ break;
+ case result_type::matrix:
+ m_matrix = r.mp_impl->m_matrix;
+ r.mp_impl->m_matrix = nullptr;
+ break;
default:
assert(!"unknown formula result type specified during copy construction.");
}
@@ -187,13 +292,15 @@ struct formula_result::impl
{
case result_type::value:
return m_value == r.mp_impl->m_value;
- break;
+ break;
case result_type::string:
return m_str_identifier == r.mp_impl->m_str_identifier;
- break;
+ break;
case result_type::error:
return m_error == r.mp_impl->m_error;
- break;
+ break;
+ case result_type::matrix:
+ return *m_matrix == *r.mp_impl->m_matrix;
default:
assert(!"unknown formula result type specified during copy construction.");
}
@@ -228,10 +335,12 @@ struct formula_result::impl
if (buf.equals("REF"))
{
+ clear_matrix();
m_error = formula_error_t::ref_result_not_available;
}
else if (buf.equals("DIV/0"))
{
+ clear_matrix();
m_error = formula_error_t::division_by_zero;
}
else
@@ -252,7 +361,10 @@ struct formula_result::impl
}
if (buf.equals("NAME"))
+ {
+ clear_matrix();
m_error = formula_error_t::name_not_found;
+ }
else
{
good = false;
@@ -298,6 +410,7 @@ struct formula_result::impl
if (!len)
throw general_error("failed to parse string result.");
+ clear_matrix();
m_type = result_type::string;
m_str_identifier = cxt.add_string(p_first, len);
}
@@ -309,6 +422,8 @@ formula_result::formula_result() :
formula_result::formula_result(const formula_result& r) :
mp_impl(ixion::make_unique<impl>(*r.mp_impl)) {}
+formula_result::formula_result(formula_result&& r) : mp_impl(std::move(r.mp_impl)) {}
+
formula_result::formula_result(double v) : mp_impl(ixion::make_unique<impl>(v)) {}
formula_result::formula_result(string_id_t strid) : mp_impl(ixion::make_unique<impl>(strid)) {}
@@ -337,6 +452,11 @@ void formula_result::set_error(formula_error_t e)
mp_impl->set_error(e);
}
+void formula_result::set_matrix(matrix mtx)
+{
+ mp_impl->set_matrix(std::move(mtx));
+}
+
double formula_result::get_value() const
{
return mp_impl->get_value();
@@ -352,6 +472,11 @@ formula_error_t formula_result::get_error() const
return mp_impl->get_error();
}
+const matrix& formula_result::get_matrix() const
+{
+ return mp_impl->get_matrix();
+}
+
formula_result::result_type formula_result::get_type() const
{
return mp_impl->get_type();
@@ -367,9 +492,9 @@ void formula_result::parse(iface::formula_model_access& cxt, const char* p, size
mp_impl->parse(cxt, p, n);
}
-formula_result& formula_result::operator= (const formula_result& r)
+formula_result& formula_result::operator= (formula_result r)
{
- mp_impl->assign_from(r);
+ mp_impl->move_from(std::move(r));
return *this;
}
diff --git a/src/libixion/formula_tokens.cpp b/src/libixion/formula_tokens.cpp
index b8b1a51..6125655 100644
--- a/src/libixion/formula_tokens.cpp
+++ b/src/libixion/formula_tokens.cpp
@@ -186,6 +186,54 @@ void formula_token::write_string(std::ostream& /*os*/) const
{
}
+struct formula_tokens_store::impl
+{
+ formula_tokens_t m_tokens;
+ size_t m_refcount;
+
+ impl() : m_refcount(0) {}
+};
+
+formula_tokens_store::formula_tokens_store() :
+ mp_impl(ixion::make_unique<impl>())
+{
+}
+
+formula_tokens_store::~formula_tokens_store()
+{
+}
+
+formula_tokens_store_ptr_t formula_tokens_store::create()
+{
+ return formula_tokens_store_ptr_t(new formula_tokens_store);
+}
+
+void formula_tokens_store::add_ref()
+{
+ ++mp_impl->m_refcount;
+}
+
+void formula_tokens_store::release_ref()
+{
+ if (--mp_impl->m_refcount == 0)
+ delete this;
+}
+
+size_t formula_tokens_store::get_reference_count() const
+{
+ return mp_impl->m_refcount;
+}
+
+formula_tokens_t& formula_tokens_store::get()
+{
+ return mp_impl->m_tokens;
+}
+
+const formula_tokens_t& formula_tokens_store::get() const
+{
+ return mp_impl->m_tokens;
+}
+
bool operator== (const formula_tokens_t& left, const formula_tokens_t& right)
{
size_t n = left.size();
diff --git a/src/libixion/formula_value_stack.cpp b/src/libixion/formula_value_stack.cpp
index 92de7c7..0b6f28a 100644
--- a/src/libixion/formula_value_stack.cpp
+++ b/src/libixion/formula_value_stack.cpp
@@ -26,15 +26,16 @@ double get_numeric_value(const iface::formula_model_access& cxt, const stack_val
switch (v.get_type())
{
case stack_value_t::value:
+ case stack_value_t::matrix:
ret = v.get_value();
- break;
+ break;
case stack_value_t::single_ref:
{
// reference to a single cell.
const abs_address_t& addr = v.get_address();
ret = cxt.get_numeric_value(addr);
+ break;
}
- break;
default:
#if IXION_DEBUG_GLOBAL
__IXION_DEBUG_OUT__ << "value is being popped, but the stack value type is not appropriate." << endl;
@@ -58,6 +59,9 @@ stack_value::stack_value(const abs_address_t& val) :
stack_value::stack_value(const abs_range_t& val) :
m_type(stack_value_t::range_ref), m_range(new abs_range_t(val)) {}
+stack_value::stack_value(matrix mtx) :
+ m_type(stack_value_t::matrix), m_matrix(new matrix(std::move(mtx))) {}
+
stack_value::~stack_value()
{
switch (m_type)
@@ -68,6 +72,9 @@ stack_value::~stack_value()
case stack_value_t::single_ref:
delete m_address;
break;
+ case stack_value_t::matrix:
+ delete m_matrix;
+ break;
case stack_value_t::string:
case stack_value_t::value:
default:
@@ -82,8 +89,15 @@ stack_value_t stack_value::get_type() const
double stack_value::get_value() const
{
- if (m_type == stack_value_t::value)
- return m_value;
+ switch (m_type)
+ {
+ case stack_value_t::value:
+ return m_value;
+ case stack_value_t::matrix:
+ return m_matrix->get_numeric(0, 0);
+ default:
+ ;
+ }
return 0.0;
}
@@ -105,6 +119,27 @@ const abs_range_t& stack_value::get_range() const
return *m_range;
}
+matrix stack_value::pop_matrix()
+{
+ switch (m_type)
+ {
+ case stack_value_t::value:
+ {
+ matrix mtx(1, 1);
+ mtx.set(0, 0, m_value);
+ return mtx;
+ }
+ case stack_value_t::matrix:
+ {
+ matrix mtx;
+ mtx.swap(*m_matrix);
+ return mtx;
+ }
+ default:
+ throw formula_error(formula_error_t::stack_error);
+ }
+}
+
value_stack_t::value_stack_t(const iface::formula_model_access& cxt) : m_context(cxt) {}
value_stack_t::iterator value_stack_t::begin()
@@ -154,6 +189,11 @@ void value_stack_t::swap(value_stack_t& other)
m_stack.swap(other.m_stack);
}
+stack_value& value_stack_t::back()
+{
+ return *m_stack.back();
+}
+
const stack_value& value_stack_t::back() const
{
return *m_stack.back();
@@ -195,6 +235,11 @@ void value_stack_t::push_range_ref(const abs_range_t& val)
m_stack.push_back(make_unique<stack_value>(val));
}
+void value_stack_t::push_matrix(matrix mtx)
+{
+ m_stack.emplace_back(make_unique<stack_value>(std::move(mtx)));
+}
+
double value_stack_t::pop_value()
{
double ret = 0.0;
@@ -243,7 +288,7 @@ const std::string value_stack_t::pop_string()
case celltype_t::formula:
{
const formula_cell* fc = m_context.get_formula_cell(addr);
- const formula_result& res = fc->get_result_cache();
+ formula_result res = fc->get_result_cache();
switch (res.get_type())
{
diff --git a/src/libixion/formula_value_stack.hpp b/src/libixion/formula_value_stack.hpp
index 8700d49..fe1929c 100644
--- a/src/libixion/formula_value_stack.hpp
+++ b/src/libixion/formula_value_stack.hpp
@@ -28,11 +28,13 @@ class matrix;
* Type of stack value which can be used as intermediate value during
* formula interpretation.
*/
-enum class stack_value_t {
+enum class stack_value_t
+{
value,
string,
single_ref,
- range_ref
+ range_ref,
+ matrix,
};
/**
@@ -41,10 +43,13 @@ enum class stack_value_t {
class stack_value
{
stack_value_t m_type;
- union {
+
+ union
+ {
double m_value;
abs_address_t* m_address;
abs_range_t* m_range;
+ matrix* m_matrix;
size_t m_str_identifier;
};
@@ -57,6 +62,7 @@ public:
explicit stack_value(size_t sid);
explicit stack_value(const abs_address_t& val);
explicit stack_value(const abs_range_t& val);
+ explicit stack_value(matrix mtx);
~stack_value();
stack_value_t get_type() const;
@@ -64,6 +70,12 @@ public:
size_t get_string() const;
const abs_address_t& get_address() const;
const abs_range_t& get_range() const;
+
+ /**
+ * Move the matrix value out from storage. The internal matrix content
+ * will be empty after this call.
+ */
+ matrix pop_matrix();
};
class value_stack_t
@@ -89,6 +101,7 @@ public:
void clear();
void swap(value_stack_t& other);
+ stack_value& back();
const stack_value& back() const;
const stack_value& operator[](size_t pos) const;
@@ -99,6 +112,7 @@ public:
void push_string(size_t sid);
void push_single_ref(const abs_address_t& val);
void push_range_ref(const abs_range_t& val);
+ void push_matrix(matrix mtx);
double pop_value();
const std::string pop_string();
diff --git a/src/libixion/function_objects.cpp b/src/libixion/function_objects.cpp
index b6d02f6..7ac96c3 100644
--- a/src/libixion/function_objects.cpp
+++ b/src/libixion/function_objects.cpp
@@ -93,50 +93,6 @@ private:
}
-formula_cell_listener_handler::formula_cell_listener_handler(
- iface::formula_model_access& cxt, const abs_address_t& addr, mode_t mode) :
- m_context(cxt),
- m_listener_tracker(cxt.get_cell_listener_tracker()),
- m_addr(addr),
- m_mode(mode)
-{
-}
-
-void formula_cell_listener_handler::operator() (const formula_token* p) const
-{
- switch (p->get_opcode())
- {
- case fop_single_ref:
- {
- abs_address_t addr = p->get_single_ref().to_abs(m_addr);
- if (m_mode == mode_add)
- {
- m_listener_tracker.add(m_addr, addr);
- }
- else
- {
- assert(m_mode == mode_remove);
- m_listener_tracker.remove(m_addr, addr);
- }
- }
- break;
- case fop_range_ref:
- {
- abs_range_t range = p->get_range_ref().to_abs(m_addr);
- if (m_mode == mode_add)
- m_context.get_cell_listener_tracker().add(m_addr, range);
- else
- {
- assert(m_mode == mode_remove);
- m_context.get_cell_listener_tracker().remove(m_addr, range);
- }
- }
- break;
- default:
- ; // ignore the rest.
- }
-}
-
cell_dependency_handler::cell_dependency_handler(
iface::formula_model_access& cxt, dependency_tracker& dep_tracker, dirty_formula_cells_t& dirty_cells) :
m_context(cxt), m_dep_tracker(dep_tracker), m_dirty_cells(dirty_cells) {}
diff --git a/src/libixion/function_objects.hpp b/src/libixion/function_objects.hpp
index b7e1d2f..bbdbad6 100644
--- a/src/libixion/function_objects.hpp
+++ b/src/libixion/function_objects.hpp
@@ -26,23 +26,6 @@ class formula_cell;
class formula_token;
struct abs_address_t;
-class formula_cell_listener_handler : public std::unary_function<formula_token*, void>
-{
-public:
- enum mode_t { mode_add, mode_remove };
-
- explicit formula_cell_listener_handler(
- iface::formula_model_access& cxt, const abs_address_t& addr, mode_t mode);
-
- void operator() (const formula_token* p) const;
-
-private:
- iface::formula_model_access& m_context;
- cell_listener_tracker& m_listener_tracker;
- const abs_address_t& m_addr;
- mode_t m_mode;
-};
-
class cell_dependency_handler : public std::unary_function<abs_address_t, void>
{
public:
diff --git a/src/libixion/global.cpp b/src/libixion/global.cpp
index b54e576..1b2b025 100644
--- a/src/libixion/global.cpp
+++ b/src/libixion/global.cpp
@@ -18,12 +18,7 @@
#include <cstdlib>
#include <sstream>
#include <fstream>
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#include <sys/time.h>
-#endif
+#include <chrono>
#define IXION_DEBUG_GLOBAL 0
@@ -40,16 +35,11 @@ const char* get_formula_result_output_separator()
double global::get_current_time()
{
-#ifdef _WIN32
- FILETIME ft;
- __int64 *time64 = (__int64 *) &ft;
- GetSystemTimeAsFileTime (&ft);
- return *time64 / 10000000.0;
-#else
- timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec + tv.tv_usec / 1000000.0;
-#endif
+ unsigned long usec_since_epoch =
+ std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::system_clock::now().time_since_epoch()).count();
+
+ return usec_since_epoch / 1000000.0;
}
void global::load_file_content(const string& filepath, string& content)
@@ -60,7 +50,7 @@ void global::load_file_content(const string& filepath, string& content)
throw file_not_found(filepath);
ostringstream os;
- os << file.rdbuf() << ' '; // extra char as the end position.
+ os << file.rdbuf();
file.close();
os.str().swap(content);
diff --git a/src/libixion/grouped_ranges.cpp b/src/libixion/grouped_ranges.cpp
new file mode 100644
index 0000000..15ed0b8
--- /dev/null
+++ b/src/libixion/grouped_ranges.cpp
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "grouped_ranges.hpp"
+
+#include "ixion/global.hpp"
+#include "ixion/model_context.hpp"
+
+namespace ixion {
+
+grouped_range_error::grouped_range_error(const std::string& msg) : general_error(msg) {}
+grouped_range_error::~grouped_range_error() throw() {}
+
+grouped_ranges::grouped_ranges() {}
+grouped_ranges::~grouped_ranges() {}
+
+void grouped_ranges::add(sheet_t sheet, const abs_rc_range_t& range, uintptr_t identity)
+{
+ sheet_type& store = fetch_sheet_store(sheet);
+
+ // TODO : ensure that the new range will not overlap with any of the
+ // existing ranges.
+ store.ranges.insert(range.first.column, range.first.row, range.last.column+1, range.last.row+1, identity);
+ store.map.insert(std::make_pair(identity, range));
+}
+
+void grouped_ranges::remove(sheet_t sheet, uintptr_t identity)
+{
+ if (size_t(sheet) >= m_sheets.size())
+ throw grouped_range_error("No grouped ranges stored on specified sheet.");
+
+ sheet_type& store = *m_sheets[sheet];
+ store.ranges.remove(identity);
+ auto it = store.map.find(identity);
+ if (it != store.map.end())
+ store.map.erase(it);
+}
+
+abs_rc_address_t grouped_ranges::move_to_origin(sheet_t sheet, const abs_rc_address_t& pos) const
+{
+ if (size_t(sheet) >= m_sheets.size())
+ return pos;
+
+ const sheet_type& store = *m_sheets[sheet];
+ ranges_type::search_result res = store.ranges.search(pos.column, pos.row); // x then y
+ size_t n = res.size();
+ assert(n <= 1); // there should never be an overlap.
+ if (!n)
+ // There is no group range at the specified position.
+ return pos;
+
+ uintptr_t identity = *res.begin();
+ auto it = store.map.find(identity);
+ if (it == store.map.end())
+ return pos;
+
+ const abs_rc_range_t& gr = it->second;
+ assert(gr.first.column <= pos.column && pos.column <= gr.last.column);
+ assert(gr.first.row <= pos.row && pos.row <= gr.last.row);
+
+ return gr.first;
+}
+
+grouped_ranges::sheet_type& grouped_ranges::fetch_sheet_store(sheet_t sheet)
+{
+ if (size_t(sheet) < m_sheets.size())
+ return *m_sheets[sheet];
+
+ // Add enough sheet stores so that the specified sheet index becomes
+ // within range.
+
+ size_t new_size = sheet + 1;
+ size_t added = new_size - m_sheets.size();
+ m_sheets.reserve(new_size);
+
+ for (size_t i = 0; i < added; ++i)
+ m_sheets.emplace_back(ixion::make_unique<sheet_type>());
+
+ assert(size_t(sheet) < m_sheets.size());
+ return *m_sheets[sheet];
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/grouped_ranges.hpp b/src/libixion/grouped_ranges.hpp
new file mode 100644
index 0000000..7907eba
--- /dev/null
+++ b/src/libixion/grouped_ranges.hpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_IXION_GROUPED_RANGES_HPP
+#define INCLUDED_IXION_GROUPED_RANGES_HPP
+
+#include "ixion/address.hpp"
+#include "ixion/exceptions.hpp"
+
+#include <mdds/rectangle_set.hpp>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+
+namespace ixion {
+
+class IXION_DLLPUBLIC grouped_range_error : public general_error
+{
+public:
+ grouped_range_error(const std::string& msg);
+ virtual ~grouped_range_error() throw() override;
+};
+
+class grouped_ranges
+{
+ using ranges_type = mdds::rectangle_set<rc_t, uintptr_t>;
+ using id_to_range_map_type = std::unordered_map<uintptr_t, abs_rc_range_t>;
+
+ struct sheet_type
+ {
+ mutable ranges_type ranges;
+ id_to_range_map_type map;
+ };
+
+ std::vector<std::unique_ptr<sheet_type>> m_sheets;
+
+public:
+ grouped_ranges();
+ ~grouped_ranges();
+
+ void add(sheet_t sheet, const abs_rc_range_t& range, uintptr_t identity);
+
+ void remove(sheet_t sheet, uintptr_t identity);
+
+ abs_rc_address_t move_to_origin(sheet_t sheet, const abs_rc_address_t& pos) const;
+
+private:
+ sheet_type& fetch_sheet_store(sheet_t sheet);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/info.cpp b/src/libixion/info.cpp
index 6d4b5c8..0a117ad 100644
--- a/src/libixion/info.cpp
+++ b/src/libixion/info.cpp
@@ -26,6 +26,16 @@ int get_version_micro()
return IXION_MICRO_VERSION;
}
+int get_api_version_major()
+{
+ return IXION_MAJOR_API_VERSION;
+}
+
+int get_api_version_minor()
+{
+ return IXION_MINOR_API_VERSION;
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/interface.cpp b/src/libixion/interface.cpp
index c566cf0..324d4d0 100644
--- a/src/libixion/interface.cpp
+++ b/src/libixion/interface.cpp
@@ -25,12 +25,12 @@ std::unique_ptr<session_handler> formula_model_access::create_session_handler()
table_handler* formula_model_access::get_table_handler()
{
- return NULL;
+ return nullptr;
}
const table_handler* formula_model_access::get_table_handler() const
{
- return NULL;
+ return nullptr;
}
}}
diff --git a/src/libixion/ixion_test.cpp b/src/libixion/ixion_test.cpp
index bc167ef..0a47f01 100644
--- a/src/libixion/ixion_test.cpp
+++ b/src/libixion/ixion_test.cpp
@@ -12,6 +12,8 @@
#include "ixion/global.hpp"
#include "ixion/macros.hpp"
#include "ixion/interface/table_handler.hpp"
+#include "ixion/config.hpp"
+#include "ixion/matrix.hpp"
#include <iostream>
#include <cassert>
@@ -76,6 +78,65 @@ void test_string_pool()
assert(s_val == cxt.get_string_identifier(IXION_ASCII("Value")));
}
+void test_formula_tokens_store()
+{
+ formula_tokens_store_ptr_t p = formula_tokens_store::create();
+ assert(p->get_reference_count() == 1);
+ auto p2 = p;
+
+ assert(p->get_reference_count() == 2);
+ assert(p2->get_reference_count() == 2);
+
+ auto p3(p);
+
+ assert(p->get_reference_count() == 3);
+ assert(p2->get_reference_count() == 3);
+ assert(p3->get_reference_count() == 3);
+
+ p3.reset();
+ assert(p->get_reference_count() == 2);
+ assert(p2->get_reference_count() == 2);
+
+ p2.reset();
+ assert(p->get_reference_count() == 1);
+ p.reset();
+}
+
+void test_matrix()
+{
+ struct check
+ {
+ size_t row;
+ size_t col;
+ double val;
+ };
+
+ std::vector<check> checks =
+ {
+ { 0, 0, 1.0 },
+ { 0, 1, 2.0 },
+ { 1, 0, 3.0 },
+ { 1, 1, 4.0 },
+ };
+
+ numeric_matrix num_mtx(2, 2);
+
+ for (const check& c : checks)
+ num_mtx(c.row, c.col) = c.val;
+
+ for (const check& c : checks)
+ assert(num_mtx(c.row, c.col) == c.val);
+
+ matrix mtx(num_mtx);
+
+ for (const check& c : checks)
+ {
+ matrix::element e = mtx.get(c.row, c.col);
+ assert(e.type == matrix::element_type::numeric);
+ assert(e.numeric == c.val);
+ }
+};
+
struct ref_name_entry
{
const char* name;
@@ -654,6 +715,7 @@ void test_parse_and_print_expressions()
// Excel A1
std::vector<const char*> exps = {
+ "\" \"",
"1/3*1.4",
"2.3*(1+2)/(34*(3-2))",
"SUM(1,2,3)",
@@ -704,6 +766,27 @@ void test_parse_and_print_expressions()
bool result = check_formula_expression(cxt, *resolver, exp);
assert(result);
}
+
+ // ODFF
+
+ exps = {
+ "\" \"",
+ "SUM([.A1];[.B1])",
+ "CONCATENATE([.A6];\" \";[.B6])",
+ };
+
+ resolver = formula_name_resolver::get(formula_name_resolver_t::odff, &cxt);
+ assert(resolver);
+
+ config cfg = cxt.get_config();
+ cfg.sep_function_arg = ';';
+ cxt.set_config(cfg);
+
+ for (const char* exp : exps)
+ {
+ bool result = check_formula_expression(cxt, *resolver, exp);
+ assert(result);
+ }
}
/**
@@ -747,7 +830,8 @@ formula_cell* insert_formula(
model_context& cxt, const abs_address_t& pos, const char* exp,
const formula_name_resolver& resolver)
{
- cxt.set_formula_cell(pos, exp, strlen(exp), resolver);
+ formula_tokens_t tokens = parse_formula_string(cxt, pos, resolver, exp, strlen(exp));
+ cxt.set_formula_cell(pos, std::move(tokens));
register_formula_cell(cxt, pos);
formula_cell* p = cxt.get_formula_cell(pos);
assert(p);
@@ -781,7 +865,8 @@ void test_model_context_storage()
// Test formula cells.
abs_address_t pos(0,3,0);
const char* exp = "SUM(1,2,3)";
- cxt.set_formula_cell(pos, exp, strlen(exp), *resolver);
+ formula_tokens_t tokens = parse_formula_string(cxt, pos, *resolver, exp, strlen(exp));
+ cxt.set_formula_cell(pos, std::move(tokens));
formula_cell* p = cxt.get_formula_cell(pos);
assert(p);
}
@@ -793,9 +878,9 @@ void test_model_context_storage()
cxt.append_sheet(IXION_ASCII("test"), 1048576, 16384);
string exp = "1";
- cxt.set_formula_cell(abs_address_t(0,0,0), &exp[0], exp.size(), *resolver);
- cxt.set_formula_cell(abs_address_t(0,2,0), &exp[0], exp.size(), *resolver);
- cxt.set_formula_cell(abs_address_t(0,1,0), &exp[0], exp.size(), *resolver);
+ cxt.set_formula_cell(abs_address_t(0,0,0), parse_formula_string(cxt, abs_address_t(0,0,0), *resolver, &exp[0], exp.size()));
+ cxt.set_formula_cell(abs_address_t(0,2,0), parse_formula_string(cxt, abs_address_t(0,2,0), *resolver, &exp[0], exp.size()));
+ cxt.set_formula_cell(abs_address_t(0,1,0), parse_formula_string(cxt, abs_address_t(0,1,0), *resolver, &exp[0], exp.size()));
}
{
@@ -958,6 +1043,9 @@ int main()
test_size();
test_string_to_double();
test_string_pool();
+ test_formula_tokens_store();
+ test_matrix();
+
test_name_resolver_excel_a1();
test_name_resolver_named_expression();
test_name_resolver_table_excel_a1();
@@ -968,6 +1056,8 @@ int main()
test_function_name_resolution();
test_model_context_storage();
test_volatile_function();
+
return EXIT_SUCCESS;
}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/ixion_test_track_deps.cpp b/src/libixion/ixion_test_track_deps.cpp
new file mode 100644
index 0000000..4b3223d
--- /dev/null
+++ b/src/libixion/ixion_test_track_deps.cpp
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ixion/model_context.hpp"
+#include "ixion/macros.hpp"
+#include "ixion/formula_name_resolver.hpp"
+#include "ixion/formula.hpp"
+#include "ixion/cell_listener_tracker.hpp"
+
+#include <cassert>
+#include <iostream>
+
+using namespace ixion;
+using namespace std;
+
+void test_single_cell_dependency()
+{
+ model_context cxt;
+ cxt.append_sheet(IXION_ASCII("One"), 400, 200);
+
+ auto resolver = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &cxt);
+
+ cxt.set_numeric_cell(abs_address_t(0,0,0), 1.0); // A1
+
+ // A2
+ abs_address_t pos(0,1,0);
+ formula_tokens_t tokens = parse_formula_string(cxt, pos, *resolver, IXION_ASCII("A1*2"));
+ formula_tokens_store_ptr_t store = formula_tokens_store::create();
+ store->get() = std::move(tokens);
+ cxt.set_formula_cell(pos, store);
+ register_formula_cell(cxt, pos);
+
+ // A3
+ pos.row = 2;
+ tokens = parse_formula_string(cxt, pos, *resolver, IXION_ASCII("A2*2"));
+ store = formula_tokens_store::create();
+ store->get() = std::move(tokens);
+ cxt.set_formula_cell(pos, store);
+ register_formula_cell(cxt, pos);
+
+ // If A1 is modified, then both A2 and A3 should get updated.
+ cell_listener_tracker& tracker = cxt.get_cell_listener_tracker();
+ dirty_formula_cells_t cells;
+ tracker.get_all_cell_listeners(abs_address_t(0,0,0), cells);
+
+ assert(cells.size() == 2);
+ assert(cells.count(abs_address_t(0,1,0)) == 1);
+ assert(cells.count(abs_address_t(0,2,0)) == 1);
+}
+
+void test_range_dependency()
+{
+ model_context cxt;
+ cxt.append_sheet(IXION_ASCII("One"), 400, 200);
+
+ cxt.set_numeric_cell(abs_address_t(0,0,0), 1.0); // A1
+ cxt.set_numeric_cell(abs_address_t(0,0,0), 2.0); // A2
+ cxt.set_numeric_cell(abs_address_t(0,0,0), 3.0); // A3
+
+ cxt.set_numeric_cell(abs_address_t(0,0,2), 4.0); // C1
+ cxt.set_numeric_cell(abs_address_t(0,0,2), 5.0); // D1
+ cxt.set_numeric_cell(abs_address_t(0,0,2), 6.0); // E1
+
+ auto resolver = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &cxt);
+
+ // C5
+ abs_address_t pos(0,4,2);
+ formula_tokens_t tokens = parse_formula_string(cxt, pos, *resolver, IXION_ASCII("SUM(A1:A3,C1:E1)"));
+ cxt.set_formula_cell(pos, std::move(tokens));
+ register_formula_cell(cxt, pos);
+
+ // A10
+ pos.row = 9;
+ pos.column = 0;
+ tokens = parse_formula_string(cxt, pos, *resolver, IXION_ASCII("C5*2"));
+ cxt.set_formula_cell(pos, std::move(tokens));
+ register_formula_cell(cxt, pos);
+
+ // If A1 is modified, both C5 and A10 should get updated.
+ modified_cells_t addrs = { abs_address_t(0,0,0) };
+ dirty_formula_cells_t cells;
+ get_all_dirty_cells(cxt, addrs, cells);
+
+ assert(cells.count(abs_address_t(0,4,2)) == 1);
+ assert(cells.count(abs_address_t(0,9,0)) == 1);
+}
+
+void test_matrix_dependency()
+{
+ model_context cxt;
+ cxt.append_sheet(IXION_ASCII("One"), 400, 200);
+
+ cxt.set_numeric_cell(abs_address_t(0,0,0), 1.0); // A1
+ cxt.set_numeric_cell(abs_address_t(0,0,0), 2.0); // A2
+ cxt.set_numeric_cell(abs_address_t(0,0,0), 3.0); // A3
+
+ cxt.set_numeric_cell(abs_address_t(0,0,2), 4.0); // C1
+ cxt.set_numeric_cell(abs_address_t(0,0,2), 5.0); // D1
+ cxt.set_numeric_cell(abs_address_t(0,0,2), 6.0); // E1
+
+ abs_range_t range;
+ range.first = abs_address_t(0,4,2); // C5
+ range.last = abs_address_t(0,6,4); // E7
+
+ auto resolver = formula_name_resolver::get(formula_name_resolver_t::excel_a1, &cxt);
+
+ // C5:E7
+ formula_tokens_t tokens = parse_formula_string(
+ cxt, range.first, *resolver, IXION_ASCII("MMULT(A1:A3,C1:E1)"));
+
+ cxt.set_grouped_formula_cells(range, std::move(tokens));
+ register_formula_cell(cxt, range.first); // Register only the top-left cell.
+
+ // A10
+ abs_address_t pos(0,9,0);
+ tokens = parse_formula_string(cxt, pos, *resolver, IXION_ASCII("C5*2"));
+ cxt.set_formula_cell(pos, std::move(tokens));
+ register_formula_cell(cxt, pos);
+
+ // If A1 is modified, both C5 and A10 should get updated.
+ modified_cells_t addrs = { abs_address_t(0,0,0) };
+ dirty_formula_cells_t cells;
+ get_all_dirty_cells(cxt, addrs, cells);
+
+ assert(cells.count(abs_address_t(0,4,2)) == 1);
+ assert(cells.count(abs_address_t(0,9,0)) == 1);
+}
+
+int main()
+{
+ test_single_cell_dependency();
+ test_range_dependency();
+ test_matrix_dependency();
+
+ return EXIT_SUCCESS;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/matrix.cpp b/src/libixion/matrix.cpp
index 5ddb897..f1b0e06 100644
--- a/src/libixion/matrix.cpp
+++ b/src/libixion/matrix.cpp
@@ -8,33 +8,91 @@
#include "ixion/matrix.hpp"
#include "ixion/global.hpp"
-#include <mdds/multi_type_matrix.hpp>
+#include <limits>
+#include <cstring>
+#include <functional>
+#include <iostream>
namespace ixion {
-typedef mdds::multi_type_matrix<mdds::mtm::std_string_trait> store_type;
+const double nan = std::numeric_limits<double>::quiet_NaN();
struct matrix::impl
{
- store_type m_data;
+ matrix_store_t m_data;
+
+ impl() {}
impl(size_t rows, size_t cols) : m_data(rows, cols) {}
+
+ impl(const std::vector<double>& array, size_t rows, size_t cols) :
+ m_data(rows, cols, array.begin(), array.end()) {}
+
impl(const impl& other) : m_data(other.m_data) {}
};
+struct numeric_matrix::impl
+{
+ std::vector<double> m_array;
+ size_t m_rows;
+ size_t m_cols;
+
+ impl() : m_rows(0), m_cols(0) {}
+
+ impl(size_t rows, size_t cols) :
+ m_array(rows * cols, 0.0), m_rows(rows), m_cols(cols) {}
+
+ impl(std::vector<double> array, size_t rows, size_t cols) :
+ m_array(std::move(array)), m_rows(rows), m_cols(cols) {}
+
+ size_t to_array_pos(size_t row, size_t col) const
+ {
+ return m_rows * col + row;
+ }
+};
+
+matrix::matrix() :
+ mp_impl(ixion::make_unique<impl>()) {}
+
matrix::matrix(size_t rows, size_t cols) :
mp_impl(ixion::make_unique<impl>(rows, cols)) {}
matrix::matrix(const matrix& other) :
- mp_impl(ixion::make_unique<impl>(*other.mp_impl)) {}
+ mp_impl(ixion::make_unique<impl>(*other.mp_impl))
+{
+}
+
+matrix::matrix(matrix&& other) :
+ mp_impl(std::move(other.mp_impl))
+{
+}
+
+matrix::matrix(const numeric_matrix& other) :
+ mp_impl(ixion::make_unique<impl>(
+ other.mp_impl->m_array, other.row_size(), other.col_size()))
+{
+}
matrix::~matrix() {}
+matrix& matrix::operator= (matrix other)
+{
+ matrix t(std::move(other));
+ swap(t);
+ return *this;
+}
+
+bool matrix::is_numeric() const
+{
+ return mp_impl->m_data.numeric();
+}
+
bool matrix::is_numeric(size_t row, size_t col) const
{
switch (mp_impl->m_data.get_type(row, col))
{
case mdds::mtm::element_numeric:
+ case mdds::mtm::element_integer:
case mdds::mtm::element_boolean:
return true;
default:
@@ -54,6 +112,32 @@ void matrix::set(size_t row, size_t col, double val)
mp_impl->m_data.set(row, col, val);
}
+matrix::element matrix::get(size_t row, size_t col) const
+{
+ element me;
+ me.type = element_type::empty;
+
+ switch (mp_impl->m_data.get_type(row, col))
+ {
+ case mdds::mtm::element_numeric:
+ me.type = element_type::numeric;
+ me.numeric = mp_impl->m_data.get_numeric(row, col);
+ break;
+ case mdds::mtm::element_integer:
+ // This is a string ID.
+ me.type = element_type::string;
+ me.string_id = mp_impl->m_data.get_integer(row, col);
+ break;
+ case mdds::mtm::element_boolean:
+ me.type = element_type::boolean;
+ me.boolean = mp_impl->m_data.get_boolean(row, col);
+ default:
+ ;
+ }
+
+ return me;
+}
+
size_t matrix::row_size() const
{
return mp_impl->m_data.size().row;
@@ -64,6 +148,124 @@ size_t matrix::col_size() const
return mp_impl->m_data.size().column;
}
+void matrix::swap(matrix& r)
+{
+ mp_impl.swap(r.mp_impl);
+}
+
+numeric_matrix matrix::as_numeric() const
+{
+ matrix_store_t::size_pair_type mtx_size = mp_impl->m_data.size();
+
+ std::vector<double> num_array(mtx_size.row*mtx_size.column, nan);
+ double* dest = num_array.data();
+
+ std::function<void(const matrix_store_t::element_block_node_type&)> f =
+ [&](const matrix_store_t::element_block_node_type& node)
+ {
+ assert(node.offset == 0);
+
+ switch (node.type)
+ {
+ case mdds::mtm::element_integer:
+ {
+ using block_type = matrix_store_t::integer_block_type;
+ auto it = block_type::begin(*node.data);
+ auto ite = block_type::end(*node.data);
+
+ for (; it != ite; ++it)
+ *dest++ = *it;
+ break;
+ }
+ case mdds::mtm::element_boolean:
+ {
+ using block_type = matrix_store_t::boolean_block_type;
+ auto it = block_type::begin(*node.data);
+ auto ite = block_type::end(*node.data);
+
+ for (; it != ite; ++it)
+ *dest++ = *it ? 1.0 : 0.0;
+ break;
+ }
+ case mdds::mtm::element_numeric:
+ {
+ using block_type = matrix_store_t::numeric_block_type;
+ const double* src = &block_type::at(*node.data, 0);
+ std::memcpy(dest, src, sizeof(double)*node.size);
+ std::advance(dest, node.size);
+ break;
+ }
+ case mdds::mtm::element_string:
+ {
+ // Skip string blocks.
+ std::advance(dest, node.size);
+ break;
+ }
+ default:
+ ;
+ }
+ };
+
+ mp_impl->m_data.walk(f);
+
+ return numeric_matrix(std::move(num_array), mtx_size.row, mtx_size.column);
+}
+
+bool matrix::operator== (const matrix& r) const
+{
+ return mp_impl->m_data == r.mp_impl->m_data;
+}
+
+bool matrix::operator!= (const matrix& r) const
+{
+ return !operator==(r);
+}
+
+numeric_matrix::numeric_matrix() : mp_impl(ixion::make_unique<impl>()) {}
+numeric_matrix::numeric_matrix(size_t rows, size_t cols) :
+ mp_impl(ixion::make_unique<impl>(rows, cols)) {}
+numeric_matrix::numeric_matrix(std::vector<double> array, size_t rows, size_t cols) :
+ mp_impl(ixion::make_unique<impl>(std::move(array), rows, cols)) {}
+
+numeric_matrix::numeric_matrix(numeric_matrix&& r) : mp_impl(std::move(r.mp_impl)) {}
+
+numeric_matrix::~numeric_matrix() {}
+
+numeric_matrix& numeric_matrix::operator= (numeric_matrix other)
+{
+ numeric_matrix t(std::move(other));
+ swap(t);
+
+ return *this;
+}
+
+double& numeric_matrix::operator() (size_t row, size_t col)
+{
+ size_t pos = mp_impl->to_array_pos(row, col);
+ return mp_impl->m_array[pos];
+}
+
+const double& numeric_matrix::operator() (size_t row, size_t col) const
+{
+ size_t pos = mp_impl->to_array_pos(row, col);
+ return mp_impl->m_array[pos];
+}
+
+void numeric_matrix::swap(numeric_matrix& r)
+{
+ mp_impl.swap(r.mp_impl);
+}
+
+size_t numeric_matrix::row_size() const
+{
+ return mp_impl->m_rows;
+}
+
+size_t numeric_matrix::col_size() const
+{
+ return mp_impl->m_cols;
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/mem_str_buf.cpp b/src/libixion/mem_str_buf.cpp
index f1af71f..1e184d0 100644
--- a/src/libixion/mem_str_buf.cpp
+++ b/src/libixion/mem_str_buf.cpp
@@ -55,6 +55,12 @@ void mem_str_buf::inc()
++m_size;
}
+void mem_str_buf::dec()
+{
+ assert(mp_buf);
+ --m_size;
+}
+
void mem_str_buf::pop_front()
{
++mp_buf;
@@ -125,6 +131,14 @@ bool mem_str_buf::operator== (const mem_str_buf& r) const
return true;
}
+char mem_str_buf::back() const
+{
+ if (!m_size)
+ return '\0';
+
+ return mp_buf[m_size-1];
+}
+
bool operator< (const mem_str_buf& left, const mem_str_buf& right)
{
// TODO: optimize this.
diff --git a/src/libixion/model_context.cpp b/src/libixion/model_context.cpp
index 5602c5d..0bcf940 100644
--- a/src/libixion/model_context.cpp
+++ b/src/libixion/model_context.cpp
@@ -17,12 +17,13 @@
#include "workbook.hpp"
#include "model_types.hpp"
+#include "calc_status.hpp"
-#include <memory>
#include <sstream>
#include <unordered_map>
#include <map>
#include <vector>
+#include <deque>
#include <iostream>
#define DEBUG_MODEL_CONTEXT 0
@@ -33,107 +34,6 @@ namespace ixion {
namespace {
-struct delete_shared_tokens : public std::unary_function<model_context::shared_tokens, void>
-{
- void operator() (const model_context::shared_tokens& v)
- {
- delete v.tokens;
- }
-};
-
-class find_tokens_by_pointer : public std::unary_function<model_context::shared_tokens, bool>
-{
- const formula_tokens_t* m_ptr;
-public:
- find_tokens_by_pointer(const formula_tokens_t* p) : m_ptr(p) {}
- bool operator() (const model_context::shared_tokens& v) const
- {
- return v.tokens == m_ptr;
- }
-};
-
-/**
- * @return true if the formula cell is stored in the model with a shared
- * formula token set, false if the formula cell has a non-shared
- * formula token set, and is not yet stored in the model.
- */
-bool set_shared_formula_tokens_to_cell(
- model_context& cxt, const abs_address_t& addr, formula_cell& fcell, const formula_tokens_t& new_tokens)
-{
- if (addr.sheet == global_scope)
- return false;
-
- // Check its neighbors for adjacent formula cells.
- if (addr.row == 0)
- return false;
-
- abs_address_t test = addr;
- test.row -= 1;
-
- if (cxt.get_celltype(test) != celltype_t::formula)
- // The neighboring cell is not a formula cell.
- return false;
-
- formula_cell* test_cell = cxt.get_formula_cell(test);
- if (!test_cell)
- // The neighboring cell is not a formula cell.
- throw general_error("formula cell doesn't exist but it should!");
-
- if (test_cell->is_shared())
- {
- size_t token_id = test_cell->get_identifier();
- const formula_tokens_t* tokens = cxt.get_shared_formula_tokens(addr.sheet, token_id);
- assert(tokens);
-
- if (new_tokens != *tokens)
- return false;
-
- // Make sure that we can extend the shared range properly.
- abs_range_t range = cxt.get_shared_formula_range(addr.sheet, token_id);
- if (range.first.sheet != addr.sheet)
- // Wrong sheet
- return false;
-
- if (range.first.column != range.last.column)
- // Must be a single column.
- return false;
-
- if (range.last.row != (addr.row - 1))
- // Last row is not immediately above the current cell.
- return false;
-
- fcell.set_identifier(token_id);
- fcell.set_shared(true);
-
- range.last.row += 1;
- cxt.set_shared_formula_range(addr.sheet, token_id, range);
- }
- else
- {
- size_t token_id = test_cell->get_identifier();
- const formula_tokens_t* tokens = cxt.get_formula_tokens(addr.sheet, token_id);
- assert(tokens);
-
- if (new_tokens != *tokens)
- return false;
-
- // Move the tokens of the master cell to the shared token storage.
- size_t shared_id = cxt.set_formula_tokens_shared(addr.sheet, token_id);
- test_cell->set_shared(true);
- test_cell->set_identifier(shared_id);
- assert(test_cell->is_shared());
- fcell.set_identifier(shared_id);
- fcell.set_shared(true);
- assert(fcell.is_shared());
- abs_range_t range;
- range.first = addr;
- range.last = addr;
- range.first.row -= 1;
- cxt.set_shared_formula_range(addr.sheet, shared_id, range);
- }
- return true;
-}
-
model_context::session_handler_factory dummy_session_handler_factory;
} // anonymous namespace
@@ -143,10 +43,6 @@ class model_context_impl
typedef std::vector<std::string> strings_type;
typedef std::vector<std::unique_ptr<std::string>> string_pool_type;
typedef std::unordered_map<mem_str_buf, string_id_t, mem_str_buf::hash> string_map_type;
- typedef std::deque<formula_tokens_t*> formula_tokens_store_type;
-
- typedef model_context::shared_tokens shared_tokens;
- typedef model_context::shared_tokens_type shared_tokens_type;
public:
model_context_impl() = delete;
@@ -155,7 +51,6 @@ public:
model_context_impl(model_context& parent) :
m_parent(parent),
- mp_config(new config),
mp_cell_listener_tracker(new cell_listener_tracker(parent)),
mp_table_handler(nullptr),
mp_session_factory(&dummy_session_handler_factory)
@@ -164,16 +59,17 @@ public:
~model_context_impl()
{
- delete mp_config;
delete mp_cell_listener_tracker;
-
- for_each(m_tokens.begin(), m_tokens.end(), delete_element<formula_tokens_t>());
- for_each(m_shared_tokens.begin(), m_shared_tokens.end(), delete_shared_tokens());
}
const config& get_config() const
{
- return *mp_config;
+ return m_config;
+ }
+
+ void set_config(const config& cfg)
+ {
+ m_config = cfg;
}
cell_listener_tracker& get_cell_listener_tracker()
@@ -211,8 +107,9 @@ public:
void set_boolean_cell(const abs_address_t& addr, bool val);
void set_string_cell(const abs_address_t& addr, const char* p, size_t n);
void set_string_cell(const abs_address_t& addr, string_id_t identifier);
- void set_formula_cell(const abs_address_t& addr, const char* p, size_t n, const formula_name_resolver& resolver);
- void set_formula_cell(const abs_address_t& addr, size_t identifier, bool shared);
+ void set_formula_cell(const abs_address_t& addr, formula_tokens_t tokens);
+ void set_formula_cell(const abs_address_t& addr, const formula_tokens_store_ptr_t& tokens);
+ void set_grouped_formula_cells(const abs_range_t& group_range, formula_tokens_t tokens);
abs_range_t get_data_range(sheet_t sheet) const;
@@ -235,7 +132,7 @@ public:
sheet_t get_sheet_index(const char* p, size_t n) const;
std::string get_sheet_name(sheet_t sheet) const;
- sheet_size_t get_sheet_size(sheet_t sheet) const;
+ rc_size_t get_sheet_size(sheet_t sheet) const;
size_t get_sheet_count() const;
sheet_t append_sheet(const char* p, size_t n, row_t row_size, col_t col_size);
@@ -248,32 +145,6 @@ public:
const column_store_t* get_column(sheet_t sheet, col_t col) const;
const column_stores_t* get_columns(sheet_t sheet) const;
- const formula_tokens_t* get_formula_tokens(sheet_t sheet, size_t identifier) const;
- size_t add_formula_tokens(sheet_t sheet, formula_tokens_t* p);
- void remove_formula_tokens(sheet_t sheet, size_t identifier);
-
- void set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula,
- const formula_name_resolver& resolver);
-
- void set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula, const char* p_range, size_t n_range,
- const formula_name_resolver& resolver);
-
- void set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula, const abs_range_t& range,
- const formula_name_resolver& resolver);
-
- void set_shared_formula(const abs_address_t& addr, size_t si);
-
- const formula_tokens_t* get_shared_formula_tokens(sheet_t sheet, size_t identifier) const;
- size_t set_formula_tokens_shared(sheet_t sheet, size_t identifier);
- abs_range_t get_shared_formula_range(sheet_t sheet, size_t identifier) const;
- void set_shared_formula_range(sheet_t sheet, size_t identifier, const abs_range_t& range);
-
double count_range(const abs_range_t& range, const values_t& values_type) const;
dirty_formula_cells_t get_all_formula_cells() const;
@@ -287,15 +158,13 @@ private:
workbook m_sheets;
- config* mp_config;
+ config m_config;
cell_listener_tracker* mp_cell_listener_tracker;
iface::table_handler* mp_table_handler;
detail::named_expressions_t m_named_expressions;
model_context::session_handler_factory* mp_session_factory;
- formula_tokens_store_type m_tokens;
- model_context::shared_tokens_type m_shared_tokens;
strings_type m_sheet_names; ///< index to sheet name map.
string_pool_type m_strings;
string_map_type m_string_map;
@@ -364,7 +233,7 @@ std::string model_context_impl::get_sheet_name(sheet_t sheet) const
return m_sheet_names[sheet];
}
-sheet_size_t model_context_impl::get_sheet_size(sheet_t sheet) const
+rc_size_t model_context_impl::get_sheet_size(sheet_t sheet) const
{
return m_sheets.at(sheet).get_sheet_size();
}
@@ -481,153 +350,6 @@ const column_stores_t* model_context_impl::get_columns(sheet_t sheet) const
return &sh.get_columns();
}
-const formula_tokens_t* model_context_impl::get_formula_tokens(sheet_t sheet, size_t identifier) const
-{
- if (m_tokens.size() <= identifier)
- return NULL;
- return m_tokens[identifier];
-}
-
-size_t model_context_impl::add_formula_tokens(sheet_t sheet, formula_tokens_t* p)
-{
- // First, search for a NULL spot.
- formula_tokens_store_type::iterator itr = std::find(
- m_tokens.begin(), m_tokens.end(), static_cast<formula_tokens_t*>(NULL));
-
- if (itr != m_tokens.end())
- {
- // NULL spot found.
- size_t pos = std::distance(m_tokens.begin(), itr);
- m_tokens[pos] = p;
- return pos;
- }
-
- size_t identifier = m_tokens.size();
- m_tokens.push_back(p);
- return identifier;
-}
-
-void model_context_impl::remove_formula_tokens(sheet_t sheet, size_t identifier)
-{
- if (m_tokens.size() >= identifier)
- return;
-
- delete m_tokens[identifier];
- m_tokens[identifier] = NULL;
-}
-
-void model_context_impl::set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula, const char* p_range, size_t n_range,
- const formula_name_resolver& resolver)
-{
- formula_name_t name_type = resolver.resolve(p_range, n_range, abs_address_t());
- abs_range_t range;
- switch (name_type.type)
- {
- case ixion::formula_name_t::cell_reference:
- range.first.sheet = name_type.address.sheet;
- range.first.row = name_type.address.row;
- range.first.column = name_type.address.col;
- range.last = range.first;
- break;
- case ixion::formula_name_t::range_reference:
- range.first.sheet = name_type.range.first.sheet;
- range.first.row = name_type.range.first.row;
- range.first.column = name_type.range.first.col;
- range.last.sheet = name_type.range.last.sheet;
- range.last.row = name_type.range.last.row;
- range.last.column = name_type.range.last.col;
- break;
- default:
- {
- std::ostringstream os;
- os << "failed to resolve shared formula range. ";
- os << "(" << string(p_range, n_range) << ")";
- throw general_error(os.str());
- }
- }
-
- set_shared_formula(addr, si, p_formula, n_formula, range, resolver);
-}
-
-void model_context_impl::set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula, const abs_range_t& range,
- const formula_name_resolver& resolver)
-{
- // Tokenize the formula string and store it.
- unique_ptr<formula_tokens_t> tokens = ixion::make_unique<formula_tokens_t>(
- parse_formula_string(m_parent, addr, resolver, p_formula, n_formula));
-
- if (si >= m_shared_tokens.size())
- m_shared_tokens.resize(si+1);
-
- m_shared_tokens[si].tokens = tokens.release();
- m_shared_tokens[si].range = range;
-}
-
-void model_context_impl::set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula,
- const formula_name_resolver& resolver)
-{
- abs_range_t range;
- range.first = addr;
- range.last = range.first;
- set_shared_formula(addr, si, p_formula, n_formula, range, resolver);
-}
-
-const formula_tokens_t* model_context_impl::get_shared_formula_tokens(sheet_t sheet, size_t identifier) const
-{
-#if DEBUG_MODEL_CONTEXT
- __IXION_DEBUG_OUT__ << "identifier: " << identifier << " shared token count: " << m_shared_tokens.size() << endl;
-#endif
- if (m_shared_tokens.size() <= identifier)
- return NULL;
-
-#if DEBUG_MODEL_CONTEXT
- __IXION_DEBUG_OUT__ << "tokens: " << m_shared_tokens[identifier].tokens << endl;
-#endif
- return m_shared_tokens[identifier].tokens;
-}
-
-size_t model_context_impl::set_formula_tokens_shared(sheet_t sheet, size_t identifier)
-{
- assert(identifier < m_tokens.size());
- formula_tokens_t* tokens = m_tokens.at(identifier);
- assert(tokens);
- m_tokens[identifier] = NULL;
-
- // First, search for a NULL spot.
- shared_tokens_type::iterator itr = std::find_if(
- m_shared_tokens.begin(), m_shared_tokens.end(),
- find_tokens_by_pointer(static_cast<const formula_tokens_t*>(NULL)));
-
- if (itr != m_shared_tokens.end())
- {
- // NULL spot found.
- size_t pos = std::distance(m_shared_tokens.begin(), itr);
- m_shared_tokens[pos].tokens = tokens;
- return pos;
- }
-
- size_t shared_identifier = m_shared_tokens.size();
- m_shared_tokens.push_back(shared_tokens(tokens));
- return shared_identifier;
-}
-
-abs_range_t model_context_impl::get_shared_formula_range(sheet_t sheet, size_t identifier) const
-{
- assert(identifier < m_shared_tokens.size());
- return m_shared_tokens.at(identifier).range;
-}
-
-void model_context_impl::set_shared_formula_range(sheet_t sheet, size_t identifier, const abs_range_t& range)
-{
- m_shared_tokens.at(identifier).range = range;
-}
-
namespace {
double count_formula_block(
@@ -641,20 +363,24 @@ double count_formula_block(
for (; pp != pp_end; ++pp)
{
const formula_cell& fc = **pp;
- const formula_result& res = fc.get_result_cache();
+ formula_result res = fc.get_result_cache();
switch (res.get_type())
{
case formula_result::result_type::value:
if (vt.is_numeric())
++ret;
- break;
+ break;
case formula_result::result_type::string:
if (vt.is_string())
++ret;
+ break;
case formula_result::result_type::error:
// TODO : how do we handle error formula cells?
- break;
+ break;
+ case formula_result::result_type::matrix:
+ // TODO : ditto
+ break;
}
}
@@ -790,16 +516,6 @@ void model_context_impl::erase_cell(const abs_address_t& addr)
worksheet& sheet = m_sheets.at(addr.sheet);
column_store_t& col_store = sheet.at(addr.column);
column_store_t::iterator& pos_hint = sheet.get_pos_hint(addr.column);
-
- mdds::mtv::element_t celltype = col_store.get_type(addr.row);
- if (celltype == element_type_formula)
- {
- const formula_cell* fcell = col_store.get<formula_cell*>(addr.row);
- assert(fcell);
- remove_formula_tokens(addr.sheet, fcell->get_identifier());
- }
-
- // Just update the hint. This call is not used during import.
pos_hint = col_store.set_empty(addr.row, addr.row);
}
@@ -836,31 +552,18 @@ void model_context_impl::set_string_cell(const abs_address_t& addr, string_id_t
pos_hint = col_store.set(pos_hint, addr.row, identifier);
}
-void model_context_impl::set_formula_cell(
- const abs_address_t& addr, const char* p, size_t n, const formula_name_resolver& resolver)
+void model_context_impl::set_formula_cell(const abs_address_t& addr, formula_tokens_t tokens)
{
- unique_ptr<formula_tokens_t> tokens =
- ixion::make_unique<formula_tokens_t>(
- parse_formula_string(m_parent, addr, resolver, p, n));
+ formula_tokens_store_ptr_t ts = formula_tokens_store::create();
+ ts->get() = std::move(tokens);
- unique_ptr<formula_cell> fcell(new formula_cell);
- if (!set_shared_formula_tokens_to_cell(m_parent, addr, *fcell, *tokens))
- {
- size_t tkid = add_formula_tokens(0, tokens.release());
- fcell->set_identifier(tkid);
- }
-
- worksheet& sheet = m_sheets.at(addr.sheet);
- column_store_t& col_store = sheet.at(addr.column);
- column_store_t::iterator& pos_hint = sheet.get_pos_hint(addr.column);
- pos_hint = col_store.set(pos_hint, addr.row, fcell.release());
+ set_formula_cell(addr, ts);
}
void model_context_impl::set_formula_cell(
- const abs_address_t& addr, size_t identifier, bool shared)
+ const abs_address_t& addr, const formula_tokens_store_ptr_t& tokens)
{
- unique_ptr<formula_cell> fcell(new formula_cell(identifier));
- fcell->set_shared(shared);
+ std::unique_ptr<formula_cell> fcell = ixion::make_unique<formula_cell>(tokens);
worksheet& sheet = m_sheets.at(addr.sheet);
column_store_t& col_store = sheet.at(addr.column);
@@ -868,6 +571,36 @@ void model_context_impl::set_formula_cell(
pos_hint = col_store.set(pos_hint, addr.row, fcell.release());
}
+void model_context_impl::set_grouped_formula_cells(
+ const abs_range_t& group_range, formula_tokens_t tokens)
+{
+ const abs_address_t& top_left = group_range.first;
+
+ rc_size_t group_size;
+ group_size.row = group_range.last.row - group_range.first.row + 1;
+ group_size.column = group_range.last.column - group_range.first.column + 1;
+
+ formula_tokens_store_ptr_t ts = formula_tokens_store::create();
+ ts->get() = std::move(tokens);
+
+ calc_status_ptr_t cs(new calc_status(group_size));
+
+ worksheet& sheet = m_sheets.at(top_left.sheet);
+
+ for (col_t col_offset = 0; col_offset < group_size.column; ++col_offset)
+ {
+ col_t col = top_left.column + col_offset;
+ column_store_t& col_store = sheet.at(col);
+ column_store_t::iterator& pos_hint = sheet.get_pos_hint(col);
+
+ for (row_t row_offset = 0; row_offset < group_size.row; ++row_offset)
+ {
+ row_t row = top_left.row + row_offset;
+ pos_hint = col_store.set(pos_hint, row, new formula_cell(row_offset, col_offset, cs, ts));
+ }
+ }
+}
+
abs_range_t model_context_impl::get_data_range(sheet_t sheet) const
{
const worksheet& cols = m_sheets.at(sheet);
@@ -1084,14 +817,16 @@ string_id_t model_context_impl::get_string_identifier_nowait(const abs_address_t
case ixion::element_type_formula:
{
const formula_cell* p = col_store.get<formula_cell*>(addr.row);
- const formula_result* res_cache = p->get_result_cache_nowait();
- if (!res_cache)
+ formula_result res_cache = p->get_result_cache_nowait();
+ formula_result::result_type rt = res_cache.get_type();
+ if (rt == formula_result::result_type::error &&
+ res_cache.get_error() == formula_error_t::no_result_error)
break;
- switch (res_cache->get_type())
+ switch (rt)
{
case formula_result::result_type::string:
- return res_cache->get_string();
+ return res_cache.get_string();
case formula_result::result_type::error:
// TODO : perhaps we should return the error string here.
default:
@@ -1134,21 +869,11 @@ std::unique_ptr<iface::session_handler> model_context::session_handler_factory::
return std::unique_ptr<iface::session_handler>();
}
-model_context::shared_tokens::shared_tokens() : tokens(NULL) {}
-model_context::shared_tokens::shared_tokens(formula_tokens_t* _tokens) : tokens(_tokens) {}
-model_context::shared_tokens::shared_tokens(const shared_tokens& r) : tokens(r.tokens), range(r.range) {}
-
-bool model_context::shared_tokens::operator== (const shared_tokens& r) const
-{
- return tokens == r.tokens && range == r.range;
-}
-
model_context::model_context() :
mp_impl(new model_context_impl(*this)) {}
model_context::~model_context()
{
- delete mp_impl;
}
const config& model_context::get_config() const
@@ -1186,16 +911,21 @@ void model_context::set_string_cell(const abs_address_t& addr, string_id_t ident
mp_impl->set_string_cell(addr, identifier);
}
-void model_context::set_formula_cell(
- const abs_address_t& addr, const char* p, size_t n, const formula_name_resolver& resolver)
+void model_context::set_formula_cell(const abs_address_t& addr, formula_tokens_t tokens)
{
- mp_impl->set_formula_cell(addr, p, n, resolver);
+ mp_impl->set_formula_cell(addr, std::move(tokens));
}
void model_context::set_formula_cell(
- const abs_address_t& addr, size_t identifier, bool shared)
+ const abs_address_t& addr, const formula_tokens_store_ptr_t& tokens)
+{
+ mp_impl->set_formula_cell(addr, tokens);
+}
+
+void model_context::set_grouped_formula_cells(
+ const abs_range_t& group_range, formula_tokens_t tokens)
{
- mp_impl->set_formula_cell(addr, identifier, shared);
+ mp_impl->set_grouped_formula_cells(group_range, std::move(tokens));
}
abs_range_t model_context::get_data_range(sheet_t sheet) const
@@ -1223,6 +953,11 @@ bool model_context::get_boolean_value(const abs_address_t& addr) const
return mp_impl->get_boolean_value(addr);
}
+void model_context::set_config(const config& cfg)
+{
+ mp_impl->set_config(cfg);
+}
+
double model_context::get_numeric_value_nowait(const abs_address_t& addr) const
{
return mp_impl->get_numeric_value_nowait(addr);
@@ -1297,57 +1032,6 @@ const iface::table_handler* model_context::get_table_handler() const
return mp_impl->get_table_handler();
}
-const formula_tokens_t* model_context::get_formula_tokens(sheet_t sheet, size_t identifier) const
-{
- return mp_impl->get_formula_tokens(sheet, identifier);
-}
-
-size_t model_context::add_formula_tokens(sheet_t sheet, formula_tokens_t* p)
-{
- return mp_impl->add_formula_tokens(sheet, p);
-}
-
-void model_context::remove_formula_tokens(sheet_t sheet, size_t identifier)
-{
- mp_impl->remove_formula_tokens(sheet, identifier);
-}
-
-void model_context::set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula, const char* p_range, size_t n_range,
- const formula_name_resolver& resolver)
-{
- mp_impl->set_shared_formula(addr, si, p_formula, n_formula, p_range, n_range, resolver);
-}
-
-void model_context::set_shared_formula(
- const abs_address_t& addr, size_t si,
- const char* p_formula, size_t n_formula,
- const formula_name_resolver& resolver)
-{
- mp_impl->set_shared_formula(addr, si, p_formula, n_formula, resolver);
-}
-
-const formula_tokens_t* model_context::get_shared_formula_tokens(sheet_t sheet, size_t identifier) const
-{
- return mp_impl->get_shared_formula_tokens(sheet, identifier);
-}
-
-size_t model_context::set_formula_tokens_shared(sheet_t sheet, size_t identifier)
-{
- return mp_impl->set_formula_tokens_shared(sheet, identifier);
-}
-
-abs_range_t model_context::get_shared_formula_range(sheet_t sheet, size_t identifier) const
-{
- return mp_impl->get_shared_formula_range(sheet, identifier);
-}
-
-void model_context::set_shared_formula_range(sheet_t sheet, size_t identifier, const abs_range_t& range)
-{
- return mp_impl->set_shared_formula_range(sheet, identifier, range);
-}
-
string_id_t model_context::append_string(const char* p, size_t n)
{
return mp_impl->append_string(p, n);
@@ -1373,7 +1057,7 @@ std::string model_context::get_sheet_name(sheet_t sheet) const
return mp_impl->get_sheet_name(sheet);
}
-sheet_size_t model_context::get_sheet_size(sheet_t sheet) const
+rc_size_t model_context::get_sheet_size(sheet_t sheet) const
{
return mp_impl->get_sheet_size(sheet);
}
@@ -1445,4 +1129,5 @@ bool model_context::empty() const
}
}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/module.cpp b/src/libixion/module.cpp
new file mode 100644
index 0000000..b6aa811
--- /dev/null
+++ b/src/libixion/module.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ixion/module.hpp"
+#include "ixion/info.hpp"
+#include "ixion/compute_engine.hpp"
+#include <sstream>
+#include <vector>
+#include <boost/filesystem.hpp>
+#ifndef _WIN32
+#include <dlfcn.h>
+#endif
+
+namespace fs = boost::filesystem;
+
+namespace ixion { namespace draft {
+
+#ifdef _WIN32
+
+void init_modules()
+{
+}
+
+#else
+
+void init_modules()
+{
+ const char* module_path = std::getenv("IXION_MODULE_PATH");
+ if (!module_path)
+ return;
+
+ static std::vector<const char*> mod_names = {
+ "cuda",
+ };
+
+ std::ostringstream os;
+ os << "ixion-" << get_api_version_major() << "." << get_api_version_minor() << "-";
+ std::string mod_prefix = os.str();
+
+ for (const char* mod_name : mod_names)
+ {
+ fs::path p(module_path);
+
+ std::ostringstream os;
+ os << mod_prefix << mod_name << ".so";
+
+ p /= os.str();
+
+ // TODO: make this cross-platform.
+ void* hdl = dlopen(p.string().data(), RTLD_NOW | RTLD_GLOBAL);
+ if (!hdl)
+ return;
+
+ typedef module_def* (*register_module_type)(void);
+ register_module_type register_module;
+ *(void**)(&register_module) = dlsym(hdl, "register_module");
+
+ if (register_module)
+ {
+ module_def* md = register_module();
+ compute_engine::add_class(
+ mod_name, md->create_compute_engine, md->destroy_compute_engine);
+ }
+ }
+}
+
+#endif
+
+}}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/libixion/types.cpp b/src/libixion/types.cpp
index 7d77acd..2688f0b 100644
--- a/src/libixion/types.cpp
+++ b/src/libixion/types.cpp
@@ -17,20 +17,44 @@ const sheet_t invalid_sheet = -2;
const string_id_t empty_string_id = std::numeric_limits<string_id_t>::max();
-sheet_size_t::sheet_size_t() : row(0), column(0) {}
-sheet_size_t::sheet_size_t(const sheet_size_t& other) : row(other.row), column(other.column) {}
-sheet_size_t::sheet_size_t(row_t _row, col_t _column) : row(_row), column(_column) {}
+rc_size_t::rc_size_t() : row(0), column(0) {}
+rc_size_t::rc_size_t(const rc_size_t& other) : row(other.row), column(other.column) {}
+rc_size_t::rc_size_t(row_t _row, col_t _column) : row(_row), column(_column) {}
+rc_size_t::~rc_size_t() {}
+
+rc_size_t& rc_size_t::operator= (const rc_size_t& other)
+{
+ row = other.row;
+ column = other.column;
+ return *this;
+}
+
+formula_group_t::formula_group_t() : size(), identity(0), grouped(false) {}
+formula_group_t::formula_group_t(const formula_group_t& r) :
+ size(r.size), identity(r.identity), grouped(r.grouped) {}
+formula_group_t::formula_group_t(const rc_size_t& group_size, uintptr_t identity, bool grouped) :
+ size(group_size), identity(identity), grouped(grouped) {}
+formula_group_t::~formula_group_t() {}
+
+formula_group_t& formula_group_t::operator= (const formula_group_t& other)
+{
+ size = other.size;
+ identity = other.identity;
+ return *this;
+}
const char* get_formula_error_name(formula_error_t fe)
{
static const char* default_err_name = "#ERR!";
static const std::vector<const char*> names = {
- "", // no error
- "#REF!", // result not available
- "#DIV/0!", // division by zero
- "#NUM!", // invalid expression
- "#NAME?" // name not found
+ "", // 0: no error
+ "#REF!", // 1: result not available
+ "#DIV/0!", // 2: division by zero
+ "#NUM!", // 3: invalid expression
+ "#NAME?", // 4: name not found
+ "#NULL!", // 5: no range intersection
+ "#VALUE!", // 6: invalid value type
};
if (static_cast<size_t>(fe) < names.size())
diff --git a/src/libixion/workbook.cpp b/src/libixion/workbook.cpp
index 51bcb90..b9d5874 100644
--- a/src/libixion/workbook.cpp
+++ b/src/libixion/workbook.cpp
@@ -29,12 +29,12 @@ worksheet::~worksheet()
std::for_each(m_columns.begin(), m_columns.end(), default_deleter<column_store_t>());
}
-sheet_size_t worksheet::get_sheet_size() const
+rc_size_t worksheet::get_sheet_size() const
{
if (m_columns.empty())
- return sheet_size_t(0, 0);
+ return rc_size_t(0, 0);
- return sheet_size_t(m_columns[0]->size(), m_columns.size());
+ return rc_size_t(m_columns[0]->size(), m_columns.size());
}
workbook::workbook() {}
diff --git a/src/libixion/workbook.hpp b/src/libixion/workbook.hpp
index 9b309ae..1a19b65 100644
--- a/src/libixion/workbook.hpp
+++ b/src/libixion/workbook.hpp
@@ -44,7 +44,7 @@ public:
detail::named_expressions_t& get_named_expressions() { return m_named_expressions; }
const detail::named_expressions_t& get_named_expressions() const { return m_named_expressions; }
- sheet_size_t get_sheet_size() const;
+ rc_size_t get_sheet_size() const;
private:
column_stores_t m_columns;
diff --git a/src/model_parser.cpp b/src/model_parser.cpp
index 7e2043d..7cceba8 100644
--- a/src/model_parser.cpp
+++ b/src/model_parser.cpp
@@ -11,6 +11,7 @@
#include "ixion/formula_name_resolver.hpp"
#include "ixion/formula_result.hpp"
#include "ixion/macros.hpp"
+#include "ixion/address_iterator.hpp"
#include <sstream>
#include <iostream>
@@ -368,43 +369,68 @@ void model_parser::parse_init()
if (cell_def.name.empty() && cell_def.value.empty())
return;
- m_dirty_cell_addrs.push_back(cell_def.pos);
+ if (cell_def.matrix_value)
+ {
+ assert(cell_def.type == ct_formula);
+ const abs_address_t& pos = cell_def.pos.first;
+
+ formula_tokens_t tokens =
+ parse_formula_string(
+ m_context, pos, *mp_name_resolver, cell_def.value.get(), cell_def.value.size());
+
+ m_context.set_grouped_formula_cells(cell_def.pos, std::move(tokens));
+ m_dirty_cells.insert(pos);
+
+ cout << "{" << get_display_range_string(cell_def.pos) << "}: (m) " << cell_def.value.str() << endl;
+ return;
+ }
+
+ abs_address_iterator iter(cell_def.pos, abs_address_iterator::direction_type::vertical);
- switch (cell_def.type)
+ for (const abs_address_t& pos : iter)
{
- case ct_formula:
- {
- m_context.set_formula_cell(cell_def.pos, cell_def.value.get(), cell_def.value.size(), *mp_name_resolver);
- m_dirty_cells.insert(cell_def.pos);
+ m_dirty_cell_addrs.push_back(pos);
- cout << get_display_cell_string(cell_def.pos) << ": (f) " << cell_def.value.str() << endl;
- break;
- }
- case ct_string:
+ switch (cell_def.type)
{
- m_context.set_string_cell(cell_def.pos, cell_def.value.get(), cell_def.value.size());
+ case ct_formula:
+ {
+ formula_tokens_t tokens =
+ parse_formula_string(
+ m_context, pos, *mp_name_resolver, cell_def.value.get(), cell_def.value.size());
- cout << get_display_cell_string(cell_def.pos) << ": (s) " << cell_def.value.str() << endl;
- break;
- }
- case ct_value:
- {
- double v = global::to_double(cell_def.value.get(), cell_def.value.size());
- m_context.set_numeric_cell(cell_def.pos, v);
+ m_context.set_formula_cell(pos, std::move(tokens));
+ m_dirty_cells.insert(pos);
- cout << get_display_cell_string(cell_def.pos) << ": (n) " << v << endl;
- break;
- }
- case ct_boolean:
- {
- bool b = global::to_bool(cell_def.value.get(), cell_def.value.size());
- m_context.set_boolean_cell(cell_def.pos, b);
+ cout << get_display_cell_string(pos) << ": (f) " << cell_def.value.str() << endl;
+ break;
+ }
+ case ct_string:
+ {
+ m_context.set_string_cell(pos, cell_def.value.get(), cell_def.value.size());
- cout << get_display_cell_string(cell_def.pos) << ": (b) " << (b ? "true" : "false") << endl;
- break;
+ cout << get_display_cell_string(pos) << ": (s) " << cell_def.value.str() << endl;
+ break;
+ }
+ case ct_value:
+ {
+ double v = global::to_double(cell_def.value.get(), cell_def.value.size());
+ m_context.set_numeric_cell(pos, v);
+
+ cout << get_display_cell_string(pos) << ": (n) " << v << endl;
+ break;
+ }
+ case ct_boolean:
+ {
+ bool b = global::to_bool(cell_def.value.get(), cell_def.value.size());
+ m_context.set_boolean_cell(pos, b);
+
+ cout << get_display_cell_string(pos) << ": (b) " << (b ? "true" : "false") << endl;
+ break;
+ }
+ default:
+ throw model_parser::parse_error("unknown content type");
}
- default:
- throw model_parser::parse_error("unknown content type");
}
}
@@ -414,59 +440,69 @@ void model_parser::parse_edit()
if (cell_def.name.empty() && cell_def.value.empty())
return;
- m_dirty_cell_addrs.push_back(cell_def.pos);
- unregister_formula_cell(m_context, cell_def.pos);
-
- if (cell_def.value.empty())
+ if (cell_def.matrix_value)
{
- // A valid name is given but with empty definition. Just remove the
- // existing cell.
- m_context.erase_cell(cell_def.pos);
+ assert(cell_def.type == ct_formula);
+ const abs_address_t& pos = cell_def.pos.first;
+
+ m_dirty_cell_addrs.push_back(pos);
+ unregister_formula_cell(m_context, pos);
+
+ formula_tokens_t tokens =
+ parse_formula_string(
+ m_context, pos, *mp_name_resolver, cell_def.value.get(), cell_def.value.size());
+
+ m_context.set_grouped_formula_cells(cell_def.pos, std::move(tokens));
+ m_dirty_cells.insert(pos);
+ register_formula_cell(m_context, pos);
return;
}
- switch (cell_def.type)
+ abs_address_iterator iter(cell_def.pos, abs_address_iterator::direction_type::vertical);
+
+ for (const abs_address_t& pos : iter)
{
- case ct_formula:
- {
-#if DEBUG_MODEL_PARSER
- __IXION_DEBUG_OUT__ << "pos: " << resolver.get_name(cell_def.pos, false) << " type: formula" << endl;
-#endif
- unregister_formula_cell(m_context, cell_def.pos);
- m_context.set_formula_cell(cell_def.pos, cell_def.value.get(), cell_def.value.size(), *mp_name_resolver);
- m_dirty_cells.insert(cell_def.pos);
- register_formula_cell(m_context, cell_def.pos);
- cout << cell_def.name.str() << ": (f) " << cell_def.value.str() << endl;
-#if DEBUG_MODEL_PARSER
- std::string s = print_formula_tokens(m_context, cell_def.pos, *tokens);
- __IXION_DEBUG_OUT__ << "formula tokens: " << s << endl;
-#endif
- }
- break;
- case ct_string:
+ m_dirty_cell_addrs.push_back(pos);
+ unregister_formula_cell(m_context, pos);
+
+ if (cell_def.value.empty())
{
-#if DEBUG_MODEL_PARSER
- __IXION_DEBUG_OUT__ << "pos: " << resolver.get_name(cell_def.pos, false) << " type: string" << endl;
-#endif
- m_context.set_string_cell(cell_def.pos, cell_def.value.get(), cell_def.value.size());
- cout << cell_def.name.str() << ": (s) " << cell_def.value.str() << endl;
+ // A valid name is given but with empty definition. Just remove the
+ // existing cell.
+ m_context.erase_cell(pos);
+ continue;
}
- break;
- case ct_value:
- {
-#if DEBUG_MODEL_PARSER
- __IXION_DEBUG_OUT__ << "pos: " << resolver.get_name(cell_def.pos, false) << " type: numeric" << endl;
-#endif
- double v = global::to_double(cell_def.value.get(), cell_def.value.size());
- m_context.set_numeric_cell(cell_def.pos, v);
- address_t pos_display(cell_def.pos);
- pos_display.set_absolute(false);
- cout << mp_name_resolver->get_name(pos_display, abs_address_t(), false) << ": (n) " << v << endl;
+ switch (cell_def.type)
+ {
+ case ct_formula:
+ {
+ formula_tokens_t tokens =
+ parse_formula_string(
+ m_context, pos, *mp_name_resolver, cell_def.value.get(), cell_def.value.size());
+
+ m_context.set_formula_cell(pos, std::move(tokens));
+ m_dirty_cells.insert(pos);
+ register_formula_cell(m_context, pos);
+ cout << get_display_cell_string(pos) << ": (f) " << cell_def.value.str() << endl;
+ }
+ break;
+ case ct_string:
+ {
+ m_context.set_string_cell(pos, cell_def.value.get(), cell_def.value.size());
+ cout << get_display_cell_string(pos) << ": (s) " << cell_def.value.str() << endl;
+ }
+ break;
+ case ct_value:
+ {
+ double v = global::to_double(cell_def.value.get(), cell_def.value.size());
+ m_context.set_numeric_cell(pos, v);
+ cout << get_display_cell_string(pos) << ": (n) " << v << endl;
+ }
+ break;
+ default:
+ throw model_parser::parse_error("unknown content type");
}
- break;
- default:
- throw model_parser::parse_error("unknown content type");
}
}
@@ -721,43 +757,134 @@ model_parser::parsed_assignment_type model_parser::parse_assignment()
model_parser::cell_def_type model_parser::parse_cell_definition()
{
+ enum class section_type
+ {
+ name,
+ braced_name,
+ after_braced_name,
+ braced_value,
+ value
+ };
+
+ section_type section = section_type::name;
+
cell_def_type ret;
ret.type = model_parser::ct_unknown;
+ char skip_next = 0;
+
mem_str_buf buf;
+ const char* line_head = mp_char;
+
for (; mp_char != mp_end && *mp_char != '\n'; ++mp_char)
{
- if (ret.name.empty() && is_separator(*mp_char))
+ if (skip_next)
{
- // Separator encountered. Set the name and clear the buffer.
- if (buf.empty())
- throw model_parser::parse_error("left hand side is empty");
-
- ret.name = buf;
- buf.clear();
- switch (*mp_char)
+ if (*mp_char != skip_next)
{
- case '=':
- ret.type = model_parser::ct_formula;
- break;
- case ':':
- ret.type = model_parser::ct_value;
- break;
- case '@':
- ret.type = model_parser::ct_string;
- break;
- default:
- ;
+ std::ostringstream os;
+ os << "'" << skip_next << "' was expected, but '" << *mp_char << "' was found.";
+ throw model_parser::parse_error(os.str());
}
+
+ skip_next = 0;
+ continue;
}
- else
+
+ switch (section)
{
- if (buf.empty())
- buf.set_start(mp_char);
- else
- buf.inc();
+ case section_type::name:
+ {
+ if (mp_char == line_head && *mp_char == '{')
+ {
+ section = section_type::braced_name;
+ continue;
+ }
+
+ if (is_separator(*mp_char))
+ {
+ // Separator encountered. Set the name and clear the buffer.
+ if (buf.empty())
+ throw model_parser::parse_error("left hand side is empty");
+
+ ret.name = buf;
+ buf.clear();
+
+ switch (*mp_char)
+ {
+ case '=':
+ ret.type = model_parser::ct_formula;
+ break;
+ case ':':
+ ret.type = model_parser::ct_value;
+ break;
+ case '@':
+ ret.type = model_parser::ct_string;
+ break;
+ default:
+ ;
+ }
+
+ section = section_type::value;
+ continue;
+ }
+
+ break;
+ }
+ case section_type::braced_name:
+ {
+ if (*mp_char == '}')
+ {
+ ret.name = buf;
+ buf.clear();
+ section = section_type::after_braced_name;
+ continue;
+ }
+
+ break;
+ }
+ case section_type::after_braced_name:
+ {
+ switch (*mp_char)
+ {
+ case '{':
+ section = section_type::braced_value;
+ ret.type = model_parser::ct_formula;
+ skip_next = '=';
+ break;
+ case '=':
+ ret.type = model_parser::ct_formula;
+ section = section_type::value;
+ break;
+ case ':':
+ ret.type = model_parser::ct_value;
+ section = section_type::value;
+ break;
+ case '@':
+ ret.type = model_parser::ct_string;
+ section = section_type::value;
+ break;
+ default:
+ {
+ std::ostringstream os;
+ os << "Unexpected character after braced name: '" << *mp_char << "'";
+ throw model_parser::parse_error(os.str());
+ }
+ }
+
+ continue; // skip this character.
+ }
+ case section_type::braced_value:
+ case section_type::value:
+ default:
+ ;
}
+
+ if (buf.empty())
+ buf.set_start(mp_char);
+ else
+ buf.inc();
}
ret.value = buf;
@@ -769,8 +896,22 @@ model_parser::cell_def_type model_parser::parse_cell_definition()
ret.type = model_parser::ct_boolean;
}
+ if (section == section_type::braced_value)
+ {
+ // Make sure that the braced value ends with '}'.
+ char last = ret.value.back();
+ if (last != '}')
+ {
+ std::ostringstream os;
+ os << "'}' was expected at the end of a braced value, but '" << last << "' was found.";
+ model_parser::parse_error(os.str());
+ }
+ ret.value.dec();
+ ret.matrix_value = true;
+ }
+
#if DEBUG_MODEL_PARSER
- __IXION_DEBUG_OUT__ << "name: " << ret.name.str() << " value: " << ret.value.str() << endl;
+ __IXION_DEBUG_OUT__ << "(name='" << ret.name.str() << "'; value='" << ret.value.str() << "')" << endl;
#endif
if (ret.name.empty())
@@ -788,15 +929,27 @@ model_parser::cell_def_type model_parser::parse_cell_definition()
formula_name_t fnt = mp_name_resolver->resolve(
ret.name.get(), ret.name.size(), abs_address_t(m_current_sheet,0,0));
- if (fnt.type != formula_name_t::cell_reference)
+ switch (fnt.type)
{
- ostringstream os;
- os << "invalid cell name: " << ret.name.str();
- throw model_parser::parse_error(os.str());
+ case formula_name_t::cell_reference:
+ {
+ ret.pos.first = to_address(fnt.address).to_abs(abs_address_t(0,0,0));
+ ret.pos.last = ret.pos.first;
+ break;
+ }
+ case formula_name_t::range_reference:
+ {
+ ret.pos = to_range(fnt.range).to_abs(abs_address_t(0,0,0));
+ break;
+ }
+ default:
+ {
+ ostringstream os;
+ os << "invalid cell name: " << ret.name.str();
+ throw model_parser::parse_error(os.str());
+ }
}
- ret.pos = abs_address_t(fnt.address.sheet, fnt.address.row, fnt.address.col);
-
return ret;
}
@@ -832,7 +985,7 @@ void model_parser::check()
case celltype_t::formula:
{
const formula_cell* fcell = m_context.get_formula_cell(addr);
- const formula_result& res_cell = fcell->get_result_cache();
+ formula_result res_cell = fcell->get_result_cache();
if (res_cell != res)
{
@@ -875,8 +1028,9 @@ void model_parser::check()
if (!ps)
throw check_error("failed to retrieve a string value for a string cell.");
+ const string* ps_expected = m_context.get_string(res.get_string());
ostringstream os;
- os << "unexpected string result: (expected: " << res.get_string() << "; actual: " << *ps << ")";
+ os << "unexpected string result: (expected: '" << *ps_expected << "'; actual: '" << *ps << "')";
throw check_error(os.str());
}
break;
@@ -894,6 +1048,14 @@ std::string model_parser::get_display_cell_string(const abs_address_t& pos) cons
return mp_name_resolver->get_name(pos_display, abs_address_t(), m_print_sheet_name);
}
+std::string model_parser::get_display_range_string(const abs_range_t& pos) const
+{
+ range_t pos_display(pos);
+ pos_display.first.set_absolute(false);
+ pos_display.last.set_absolute(false);
+ return mp_name_resolver->get_name(pos_display, abs_address_t(), m_print_sheet_name);
+}
+
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/src/model_parser.hpp b/src/model_parser.hpp
index 5a27603..e8be31a 100644
--- a/src/model_parser.hpp
+++ b/src/model_parser.hpp
@@ -63,7 +63,9 @@ class model_parser
mem_str_buf name;
mem_str_buf value;
cell_type type;
- abs_address_t pos;
+ abs_range_t pos;
+
+ bool matrix_value = false;
};
public:
@@ -117,6 +119,7 @@ private:
void check();
std::string get_display_cell_string(const abs_address_t& pos) const;
+ std::string get_display_range_string(const abs_range_t& pos) const;
private:
diff --git a/src/python/Makefile.in b/src/python/Makefile.in
index c7eb583..e043756 100644
--- a/src/python/Makefile.in
+++ b/src/python/Makefile.in
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.15 from Makefile.am.
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
# @configure_input@
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@@ -416,11 +416,17 @@ AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_FILESYSTEM_LDFLAGS = @BOOST_FILESYSTEM_LDFLAGS@
+BOOST_FILESYSTEM_LDPATH = @BOOST_FILESYSTEM_LDPATH@
+BOOST_FILESYSTEM_LIBS = @BOOST_FILESYSTEM_LIBS@
BOOST_LDPATH = @BOOST_LDPATH@
BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
BOOST_ROOT = @BOOST_ROOT@
+BOOST_SYSTEM_LDFLAGS = @BOOST_SYSTEM_LDFLAGS@
+BOOST_SYSTEM_LDPATH = @BOOST_SYSTEM_LDPATH@
+BOOST_SYSTEM_LIBS = @BOOST_SYSTEM_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
@@ -451,8 +457,10 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
IXION_API_VERSION = @IXION_API_VERSION@
+IXION_MAJOR_API_VERSION = @IXION_MAJOR_API_VERSION@
IXION_MAJOR_VERSION = @IXION_MAJOR_VERSION@
IXION_MICRO_VERSION = @IXION_MICRO_VERSION@
+IXION_MINOR_API_VERSION = @IXION_MINOR_API_VERSION@
IXION_MINOR_VERSION = @IXION_MINOR_VERSION@
IXION_VERSION = @IXION_VERSION@
LD = @LD@
diff --git a/src/python/sheet.cpp b/src/python/sheet.cpp
index fea2bcb..77529ec 100644
--- a/src/python/sheet.cpp
+++ b/src/python/sheet.cpp
@@ -152,7 +152,12 @@ PyObject* sheet_set_formula_cell(sheet* self, PyObject* args, PyObject* kwargs)
ixion::abs_address_t pos(sd->m_sheet_index, row, col);
sd->m_global->m_modified_cells.push_back(pos);
sd->m_global->m_dirty_formula_cells.insert(pos);
- cxt.set_formula_cell(pos, formula, strlen(formula), *sd->m_global->m_resolver);
+
+ ixion::formula_tokens_t tokens =
+ ixion::parse_formula_string(
+ cxt, pos, *sd->m_global->m_resolver, formula, strlen(formula));
+
+ cxt.set_formula_cell(pos, std::move(tokens));
// Put this formula cell in a dependency chain.
ixion::register_formula_cell(cxt, pos);
@@ -250,16 +255,9 @@ PyObject* sheet_get_formula_expression(sheet* self, PyObject* args, PyObject* kw
return nullptr;
}
- size_t tid = fc->get_identifier();
- const formula_tokens_t* ft = cxt.get_formula_tokens(sd->m_sheet_index, tid);
- if (!ft)
- {
- PyErr_SetString(PyExc_RuntimeError,
- "Failed to retrieve a formula tokens object from a token ID.");
- return nullptr;
- }
+ const ixion::formula_tokens_t& ft = fc->get_tokens()->get();
- string str = ixion::print_formula_tokens(cxt, pos, *sd->m_global->m_resolver, *ft);
+ string str = ixion::print_formula_tokens(cxt, pos, *sd->m_global->m_resolver, ft);
if (str.empty())
return PyUnicode_FromString("");