summaryrefslogtreecommitdiffstats
path: root/include/ixion
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--include/ixion/Makefile.am31
-rw-r--r--include/ixion/Makefile.in752
-rw-r--r--include/ixion/address.hpp347
-rw-r--r--include/ixion/address_iterator.hpp67
-rw-r--r--include/ixion/cell.hpp132
-rw-r--r--include/ixion/cell_access.hpp67
-rw-r--r--include/ixion/compute_engine.hpp89
-rw-r--r--include/ixion/config.hpp50
-rw-r--r--include/ixion/dirty_cell_tracker.hpp97
-rw-r--r--include/ixion/document.hpp94
-rw-r--r--include/ixion/env.hpp61
-rw-r--r--include/ixion/exceptions.hpp98
-rw-r--r--include/ixion/formula.hpp217
-rw-r--r--include/ixion/formula_function_opcode.hpp370
-rw-r--r--include/ixion/formula_name_resolver.hpp129
-rw-r--r--include/ixion/formula_opcode.hpp61
-rw-r--r--include/ixion/formula_result.hpp136
-rw-r--r--include/ixion/formula_tokens.hpp215
-rw-r--r--include/ixion/formula_tokens_fwd.hpp27
-rw-r--r--include/ixion/global.hpp35
-rw-r--r--include/ixion/info.hpp26
-rw-r--r--include/ixion/interface/Makefile.am6
-rw-r--r--include/ixion/interface/Makefile.in611
-rw-r--r--include/ixion/interface/session_handler.hpp50
-rw-r--r--include/ixion/interface/table_handler.hpp63
-rw-r--r--include/ixion/macros.hpp18
-rw-r--r--include/ixion/matrix.hpp122
-rw-r--r--include/ixion/model_context.hpp446
-rw-r--r--include/ixion/model_iterator.hpp76
-rw-r--r--include/ixion/module.hpp37
-rw-r--r--include/ixion/named_expressions_iterator.hpp57
-rw-r--r--include/ixion/table.hpp34
-rw-r--r--include/ixion/types.hpp373
33 files changed, 4994 insertions, 0 deletions
diff --git a/include/ixion/Makefile.am b/include/ixion/Makefile.am
new file mode 100644
index 0000000..364bd6a
--- /dev/null
+++ b/include/ixion/Makefile.am
@@ -0,0 +1,31 @@
+SUBDIRS = interface
+
+libixiondir = $(includedir)/libixion-@IXION_API_VERSION@/ixion
+libixion_HEADERS = \
+ address.hpp \
+ address_iterator.hpp \
+ cell.hpp \
+ cell_access.hpp \
+ compute_engine.hpp \
+ config.hpp \
+ dirty_cell_tracker.hpp \
+ document.hpp \
+ env.hpp \
+ exceptions.hpp \
+ formula_function_opcode.hpp \
+ formula.hpp \
+ formula_name_resolver.hpp \
+ formula_opcode.hpp \
+ formula_result.hpp \
+ formula_tokens.hpp \
+ formula_tokens_fwd.hpp \
+ global.hpp \
+ info.hpp \
+ macros.hpp \
+ matrix.hpp \
+ model_context.hpp \
+ model_iterator.hpp \
+ module.hpp \
+ named_expressions_iterator.hpp \
+ table.hpp \
+ types.hpp
diff --git a/include/ixion/Makefile.in b/include/ixion/Makefile.in
new file mode 100644
index 0000000..faab7a8
--- /dev/null
+++ b/include/ixion/Makefile.in
@@ -0,0 +1,752 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/ixion
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(libixion_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libixiondir)"
+HEADERS = $(libixion_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir distdir-am
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+DIST_SUBDIRS = $(SUBDIRS)
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+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@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+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@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VULKAN_CFLAGS = @VULKAN_CFLAGS@
+VULKAN_LIBS = @VULKAN_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = interface
+libixiondir = $(includedir)/libixion-@IXION_API_VERSION@/ixion
+libixion_HEADERS = \
+ address.hpp \
+ address_iterator.hpp \
+ cell.hpp \
+ cell_access.hpp \
+ compute_engine.hpp \
+ config.hpp \
+ dirty_cell_tracker.hpp \
+ document.hpp \
+ env.hpp \
+ exceptions.hpp \
+ formula_function_opcode.hpp \
+ formula.hpp \
+ formula_name_resolver.hpp \
+ formula_opcode.hpp \
+ formula_result.hpp \
+ formula_tokens.hpp \
+ formula_tokens_fwd.hpp \
+ global.hpp \
+ info.hpp \
+ macros.hpp \
+ matrix.hpp \
+ model_context.hpp \
+ model_iterator.hpp \
+ module.hpp \
+ named_expressions_iterator.hpp \
+ table.hpp \
+ types.hpp
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/ixion/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/ixion/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-libixionHEADERS: $(libixion_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(libixion_HEADERS)'; test -n "$(libixiondir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libixiondir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libixiondir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libixiondir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libixiondir)" || exit $$?; \
+ done
+
+uninstall-libixionHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libixion_HEADERS)'; test -n "$(libixiondir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libixiondir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(HEADERS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libixiondir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-libixionHEADERS
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-libixionHEADERS
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean 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-libixionHEADERS install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-libixionHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/ixion/address.hpp b/include/ixion/address.hpp
new file mode 100644
index 0000000..aed09a2
--- /dev/null
+++ b/include/ixion/address.hpp
@@ -0,0 +1,347 @@
+/* -*- 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_HPP
+#define INCLUDED_IXION_ADDRESS_HPP
+
+#include "types.hpp"
+
+#include <string>
+#include <vector>
+#include <ostream>
+#include <unordered_set>
+
+namespace ixion {
+
+/**
+ * Row address not specified. This is used to reference an entire column
+ * when a specific column address is given.
+ */
+IXION_DLLPUBLIC_VAR const row_t row_unset;
+
+/**
+ * Highest number that can be used to reference a row address. Numbers
+ * higher than this number are all used as special indices.
+ */
+IXION_DLLPUBLIC_VAR const row_t row_upper_bound;
+
+/**
+ * Column address not specified. This is used to reference an entire row
+ * when a specific row address is given.
+ */
+IXION_DLLPUBLIC_VAR const col_t column_unset;
+
+/**
+ * Highest number that can be used to reference a column address. Numbers
+ * higher than this number are all used as special indices.
+ */
+IXION_DLLPUBLIC_VAR const col_t column_upper_bound;
+
+/**
+ * Stores absolute address, and absolute address only.
+ */
+struct IXION_DLLPUBLIC abs_address_t
+{
+ enum init_invalid { invalid };
+
+ sheet_t sheet;
+ row_t row;
+ col_t column;
+
+ abs_address_t();
+ abs_address_t(init_invalid);
+ abs_address_t(sheet_t _sheet, row_t _row, col_t _column);
+ abs_address_t(const abs_address_t& r);
+
+ bool valid() const;
+ ::std::string get_name() const;
+
+ struct hash
+ {
+ IXION_DLLPUBLIC size_t operator() (const abs_address_t& addr) const;
+ };
+};
+
+IXION_DLLPUBLIC bool operator==(const abs_address_t& left, const abs_address_t& right);
+IXION_DLLPUBLIC bool operator!=(const abs_address_t& left, const abs_address_t& right);
+IXION_DLLPUBLIC bool operator<(const abs_address_t& left, const abs_address_t& right);
+
+/**
+ * Stores either absolute or relative address.
+ */
+struct IXION_DLLPUBLIC address_t
+{
+ sheet_t sheet;
+ row_t row;
+ col_t column;
+ bool abs_sheet:1;
+ bool abs_row:1;
+ bool abs_column:1;
+
+ address_t();
+ address_t(sheet_t _sheet, row_t _row, col_t _column,
+ bool _abs_sheet=true, bool _abs_row=true, bool _abs_column=true);
+ address_t(const address_t& r);
+ address_t(const abs_address_t& r);
+
+ bool valid() const;
+ abs_address_t to_abs(const abs_address_t& origin) const;
+ ::std::string get_name() const;
+
+ void set_absolute(bool abs);
+
+ struct hash
+ {
+ IXION_DLLPUBLIC size_t operator() (const address_t& addr) const;
+ };
+};
+
+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);
+ abs_rc_address_t(const abs_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 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.
+ */
+struct IXION_DLLPUBLIC abs_range_t
+{
+ enum init_invalid { invalid };
+
+ abs_address_t first;
+ abs_address_t last;
+
+ abs_range_t();
+ abs_range_t(init_invalid);
+ abs_range_t(sheet_t _sheet, row_t _row, col_t _col);
+
+ /**
+ * @param _sheet 0-based sheet index.
+ * @param _row 0-based row position of the top-left cell of the range.
+ * @param _col 0-based column position of the top-left cell of the range.
+ * @param _row_span row length of the range. It must be 1 or greater.
+ * @param _col_span column length of the range. It must be 1 or greater.
+ */
+ abs_range_t(sheet_t _sheet, row_t _row, col_t _col, row_t _row_span, col_t _col_span);
+ abs_range_t(const abs_address_t& addr);
+ abs_range_t(const abs_address_t& addr, row_t row_span, col_t col_span);
+
+ struct hash
+ {
+ IXION_DLLPUBLIC size_t operator() (const abs_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_address_t& addr) const;
+
+ /**
+ * Reorder range values as needed to ensure the range is valid.
+ */
+ void reorder();
+};
+
+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);
+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);
+ abs_rc_range_t(const abs_rc_range_t& other);
+ abs_rc_range_t(const abs_range_t& other);
+
+ 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.
+ */
+struct IXION_DLLPUBLIC range_t
+{
+ address_t first;
+ address_t last;
+
+ range_t();
+ range_t(const address_t& _first, const address_t& _last);
+ range_t(const range_t& r);
+ range_t(const abs_range_t& r);
+
+ 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;
+
+ abs_range_t to_abs(const abs_address_t& origin) const;
+
+ void set_absolute(bool abs);
+
+ struct hash
+ {
+ IXION_DLLPUBLIC size_t operator() (const range_t& range) const;
+ };
+};
+
+IXION_DLLPUBLIC bool operator==(const range_t& left, const range_t& right);
+IXION_DLLPUBLIC bool operator!=(const range_t& left, const range_t& right);
+
+IXION_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const abs_address_t& addr);
+IXION_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const abs_rc_address_t& addr);
+IXION_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const address_t& addr);
+IXION_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const abs_range_t& range);
+IXION_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const abs_rc_range_t& range);
+IXION_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const range_t& range);
+
+/**
+ * Type that represents a collection of multiple absolute cell addresses.
+ */
+using abs_address_set_t = std::unordered_set<abs_address_t, abs_address_t::hash>;
+using abs_range_set_t = std::unordered_set<abs_range_t, abs_range_t::hash>;
+using abs_rc_range_set_t = std::unordered_set<abs_rc_range_t, abs_rc_range_t::hash>;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/address_iterator.hpp b/include/ixion/address_iterator.hpp
new file mode 100644
index 0000000..9250444
--- /dev/null
+++ b/include/ixion/address_iterator.hpp
@@ -0,0 +1,67 @@
+/* -*- 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 "types.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:
+ 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, rc_direction_t 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, rc_direction_t 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
new file mode 100644
index 0000000..59f09bb
--- /dev/null
+++ b/include/ixion/cell.hpp
@@ -0,0 +1,132 @@
+/* -*- 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_CELL_HPP
+#define INCLUDED_IXION_CELL_HPP
+
+#include "types.hpp"
+#include "formula_tokens_fwd.hpp"
+
+#include <memory>
+#include <vector>
+#include <string>
+
+namespace ixion {
+
+class formula_result;
+class formula_cell;
+class model_context;
+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>;
+
+class IXION_DLLPUBLIC formula_cell
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ formula_cell(const formula_cell&) = delete;
+ formula_cell& operator= (formula_cell) = delete;
+
+ formula_cell();
+ 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();
+
+ const formula_tokens_store_ptr_t& get_tokens() const;
+ void set_tokens(const formula_tokens_store_ptr_t& tokens);
+
+ double get_value(formula_result_wait_policy_t policy) const;
+ std::string_view get_string(formula_result_wait_policy_t policy) const;
+
+ void interpret(model_context& context, const abs_address_t& pos);
+
+ /**
+ * Determine if this cell contains circular reference by walking through
+ * all its reference tokens.
+ */
+ void check_circular(const model_context& cxt, const abs_address_t& pos);
+
+ /**
+ * Reset cell's internal state.
+ */
+ void reset();
+
+ /**
+ * Get a series of all reference tokens included in the formula
+ * expression stored in this cell.
+ *
+ * @param cxt model context instance.
+ * @param pos position of the cell.
+ *
+ * @return an array of reference formula tokens. Each element is a
+ * pointer to the actual token instance stored in the cell object.
+ * Be aware that the pointer is valid only as long as the actual
+ * token instance is alive.
+ */
+ std::vector<const formula_token*> get_ref_tokens(
+ const model_context& cxt, const abs_address_t& pos) const;
+
+ /**
+ * Get the cached result without post-processing in case of a grouped
+ * formula cell.
+ *
+ * @param policy action to take in case the result is not yet available.
+ *
+ * @return formula result.
+ */
+ const formula_result& get_raw_result_cache(formula_result_wait_policy_t policy) const;
+
+ /**
+ * Get the cached result as a single cell. For a non-grouped formula
+ * cell, it should be identical to the value from the get_raw_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.
+ *
+ * @param policy action to take in case the result is not yet available.
+ *
+ * @return formula result.
+ */
+ formula_result get_result_cache(formula_result_wait_policy_t policy) const;
+
+ /**
+ * Set a cached result to this formula cell instance.
+ *
+ *
+ * @param result cached result.
+ */
+ void set_result_cache(formula_result result);
+
+ 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;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/cell_access.hpp b/include/ixion/cell_access.hpp
new file mode 100644
index 0000000..63c5323
--- /dev/null
+++ b/include/ixion/cell_access.hpp
@@ -0,0 +1,67 @@
+/* -*- 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_CELL_ACCESS_HPP
+#define INCLUDED_IXION_CELL_ACCESS_HPP
+
+#include "types.hpp"
+
+#include <memory>
+#include <string>
+
+namespace ixion {
+
+class model_context;
+class formula_cell;
+class formula_result;
+struct abs_address_t;
+
+/**
+ * This class provides a read-only access to a single cell. It's more
+ * efficient to use this class if you need to make multiple successive
+ * queries to the same cell.
+ *
+ * Note that an instance of this class will get invalidated when the content
+ * of ixion::model_context is modified.
+ */
+class IXION_DLLPUBLIC cell_access
+{
+ friend class model_context;
+
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+ cell_access(const model_context& cxt, const abs_address_t& addr);
+public:
+ cell_access(cell_access&& other);
+ cell_access& operator= (cell_access&& other);
+ ~cell_access();
+
+ celltype_t get_type() const;
+
+ cell_value_t get_value_type() const;
+
+ const formula_cell* get_formula_cell() const;
+
+ formula_result get_formula_result() const;
+
+ double get_numeric_value() const;
+
+ bool get_boolean_value() const;
+
+ std::string_view get_string_value() const;
+
+ string_id_t get_string_identifier() const;
+
+ formula_error_t get_error_value() const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/compute_engine.hpp b/include/ixion/compute_engine.hpp
new file mode 100644
index 0000000..6e5bbd7
--- /dev/null
+++ b/include/ixion/compute_engine.hpp
@@ -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/.
+ */
+
+#ifndef INCLUDED_IXION_COMPUTE_ENGINE_HPP
+#define INCLUDED_IXION_COMPUTE_ENGINE_HPP
+
+#include "env.hpp"
+#include "module.hpp"
+
+#include <memory>
+#include <string>
+
+namespace ixion { namespace draft {
+
+enum class array_type { unknown, float32, float64, uint32 };
+
+struct array
+{
+ union
+ {
+ float* float32;
+ double* float64;
+ uint32_t* uint32;
+ void* data;
+ };
+
+ array_type type = array_type::unknown;
+ std::size_t size = 0u;
+};
+
+/**
+ * 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 an empty name 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(std::string_view name = std::string_view());
+
+ /**
+ * Add a new compute engine class.
+ *
+ * @param hdl handler for the dynamically-loaded module in which the
+ * compute engine being registered resides.
+ * @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(
+ void* hdl, std::string_view name, create_compute_engine_t func_create, destroy_compute_engine_t func_destroy);
+
+ compute_engine();
+ virtual ~compute_engine();
+
+ virtual std::string_view get_name() const;
+
+ virtual void compute_fibonacci(array& io);
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/config.hpp b/include/ixion/config.hpp
new file mode 100644
index 0000000..9575ac3
--- /dev/null
+++ b/include/ixion/config.hpp
@@ -0,0 +1,50 @@
+/* -*- 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_CONFIG_HPP
+#define INCLUDED_IXION_CONFIG_HPP
+
+#include "types.hpp"
+
+namespace ixion {
+
+/**
+ * This structure store parameters that influence various aspects of the
+ * ixion formula engine.
+ */
+struct IXION_DLLPUBLIC config
+{
+ /**
+ * Function argument separator. By default it's ','.
+ */
+ 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);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/dirty_cell_tracker.hpp b/include/ixion/dirty_cell_tracker.hpp
new file mode 100644
index 0000000..b701044
--- /dev/null
+++ b/include/ixion/dirty_cell_tracker.hpp
@@ -0,0 +1,97 @@
+/* -*- 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_DIRTY_CELL_TRACKER_HPP
+#define INCLUDED_IXION_DIRTY_CELL_TRACKER_HPP
+
+#include "address.hpp"
+
+#include <memory>
+
+namespace ixion {
+
+/**
+ * This class is designed to track in-direct dependencies of dirty formula
+ * cells. A "dirty" formula cell is a formula cell whose result needs to be
+ * re-calculated because at least one of its references have their values
+ * updated.
+ *
+ * This class also takes volatile functions into account when determining
+ * the status of the formula cel result. A volatile function is a cell
+ * function whose value needs to get re-calculated unconditionally on every
+ * re-calculation. One example of a volatile function is NOW(), which
+ * returns the current time at the time of calculation.
+ */
+class IXION_DLLPUBLIC dirty_cell_tracker
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ dirty_cell_tracker(const dirty_cell_tracker&) = delete;
+ dirty_cell_tracker& operator= (const dirty_cell_tracker&) = delete;
+
+ dirty_cell_tracker();
+ ~dirty_cell_tracker();
+
+ /**
+ * Add a tracking relationship from a source cell or cell range to a
+ * destination cell or cell range.
+ *
+ * @param src source cell or cell range that includes reference to
+ * (therefore listens to) the range.
+ * @param dest destination cell or range referenced tracked by the source
+ * cell.
+ */
+ void add(const abs_range_t& src, const abs_range_t& dest);
+
+ /**
+ * Remove an existing tracking relationship from a source cell or cell
+ * range to a destination cell or cell range. If no such relationship
+ * exists, it does nothing.
+ *
+ * @param src cell or cell range that includes reference to the range.
+ * @param dest cell or range referenced by the cell.
+ */
+ void remove(const abs_range_t& src, const abs_range_t& dest);
+
+ /**
+ * Register a formula cell located at the specified position as volatile.
+ * Note that the caller should ensure that the cell at the specified
+ * position is indeed a formula cell.
+ *
+ * @param pos position of the cell to register as a volatile cell.
+ */
+ void add_volatile(const abs_range_t& pos);
+
+ /**
+ * Remove the specified cell position from the internal set of registered
+ * volatile formula cells.
+ *
+ * @param pos position of the cell to unregister as a volatile cell.
+ */
+ void remove_volatile(const abs_range_t& pos);
+
+ abs_range_set_t query_dirty_cells(const abs_range_t& modified_cell) const;
+
+ abs_range_set_t query_dirty_cells(const abs_range_set_t& modified_cells) const;
+
+ std::vector<abs_range_t> query_and_sort_dirty_cells(const abs_range_t& modified_cell) const;
+
+ std::vector<abs_range_t> query_and_sort_dirty_cells(
+ const abs_range_set_t& modified_cells, const abs_range_set_t* dirty_formula_cells = nullptr) const;
+
+ std::string to_string() const;
+
+ bool empty() const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/document.hpp b/include/ixion/document.hpp
new file mode 100644
index 0000000..a612898
--- /dev/null
+++ b/include/ixion/document.hpp
@@ -0,0 +1,94 @@
+/* -*- 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_DOCUMENT_HPP
+#define INCLUDED_IXION_DOCUMENT_HPP
+
+#include "types.hpp"
+#include "address.hpp"
+
+#include <memory>
+#include <string>
+#include <variant>
+
+namespace ixion {
+
+class cell_access;
+
+/**
+ * Higher level document representation designed to handle both cell value
+ * storage as well as formula cell calculations.
+ */
+class IXION_DLLPUBLIC document
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+public:
+ document();
+
+ /**
+ * Constructor with custom cell address type.
+ *
+ * @param cell_address_type cell address type to use for cell addresses
+ * represented by string values.
+ */
+ document(formula_name_resolver_t cell_address_type);
+ ~document();
+
+ struct IXION_DLLPUBLIC cell_pos
+ {
+ enum class cp_type { string, address };
+ cp_type type;
+
+ std::variant<std::string_view, ixion::abs_address_t> value;
+
+ cell_pos(const char* p);
+ cell_pos(const char* p, size_t n);
+ cell_pos(const std::string& s);
+ cell_pos(const abs_address_t& addr);
+ };
+
+ void append_sheet(std::string name);
+
+ /**
+ * Set a new name to an existing sheet.
+ *
+ * @param sheet 0-based sheet index.
+ * @param name New name of a sheet.
+ */
+ void set_sheet_name(sheet_t sheet, std::string name);
+
+ cell_access get_cell_access(cell_pos pos) const;
+
+ void set_numeric_cell(cell_pos pos, double val);
+
+ void set_string_cell(cell_pos pos, std::string_view s);
+
+ void set_boolean_cell(cell_pos pos, bool val);
+
+ void empty_cell(cell_pos pos);
+
+ double get_numeric_value(cell_pos pos) const;
+
+ std::string_view get_string_value(cell_pos pos) const;
+
+ void set_formula_cell(cell_pos pos, std::string_view formula);
+
+ /**
+ * Calculate all the "dirty" formula cells in the document.
+ *
+ * @param thread_count number of threads to use to perform calculation.
+ * When 0 is specified, it only uses the main thread.
+ */
+ void calculate(size_t thread_count);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/env.hpp b/include/ixion/env.hpp
new file mode 100644
index 0000000..c164a1d
--- /dev/null
+++ b/include/ixion/env.hpp
@@ -0,0 +1,61 @@
+/* -*- 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_ENV_HPP
+#define INCLUDED_IXION_ENV_HPP
+
+#if defined _WIN32 || defined __CYGWIN__
+ #if defined __MINGW32__
+ #define IXION_DLLPUBLIC
+ #define IXION_DLLPUBLIC_VAR extern
+ #elif defined IXION_BUILD
+ #ifdef DLL_EXPORT
+ #define IXION_DLLPUBLIC __declspec(dllexport)
+ #define IXION_DLLPUBLIC_VAR extern __declspec(dllexport)
+ #else
+ #define IXION_DLLPUBLIC
+ #define IXION_DLLPUBLIC_VAR extern
+ #endif
+ #else
+ #define IXION_DLLPUBLIC __declspec(dllimport)
+ #define IXION_DLLPUBLIC_VAR extern __declspec(dllimport)
+ #endif
+ #define IXION_DLLLOCAL
+#else
+ #if defined __GNUC__ && __GNUC__ >= 4
+ #define IXION_DLLPUBLIC __attribute__ ((visibility ("default")))
+ #define IXION_DLLLOCAL __attribute__ ((visibility ("hidden")))
+ #else
+ #define IXION_DLLPUBLIC
+ #define IXION_DLLLOCAL
+ #endif
+ #define IXION_DLLPUBLIC_VAR IXION_DLLPUBLIC extern
+#endif
+
+#if _WIN32
+#define IXION_MOD_EXPORT __declspec(dllexport)
+#else
+#define IXION_MOD_EXPORT __attribute__ ((visibility ("default")))
+#endif
+
+#if defined(IXION_TRACE_ON) || defined(IXION_DEBUG_ON)
+#define IXION_LOGGING 1
+#else
+#define IXION_LOGGING 0
+#endif
+
+#ifdef __GNUC__
+ #define IXION_DEPRECATED __attribute__ ((deprecated))
+#elif defined(_MSC_VER)
+ #define IXION_DEPRECATED __declspec(deprecated)
+#else
+ #define IXION_DEPRECATED
+#endif
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/exceptions.hpp b/include/ixion/exceptions.hpp
new file mode 100644
index 0000000..bccceb1
--- /dev/null
+++ b/include/ixion/exceptions.hpp
@@ -0,0 +1,98 @@
+/* -*- 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_EXCEPTIONS_HPP
+#define INCLUDED_IXION_EXCEPTIONS_HPP
+
+#include "env.hpp"
+#include "types.hpp"
+
+#include <exception>
+#include <string>
+#include <memory>
+
+namespace ixion {
+
+class IXION_DLLPUBLIC general_error : public std::exception
+{
+public:
+ general_error();
+ explicit general_error(const std::string& msg);
+ virtual ~general_error();
+ virtual const char* what() const noexcept override;
+
+protected:
+ void set_message(const std::string& msg);
+
+private:
+ std::string m_msg;
+};
+
+class IXION_DLLPUBLIC formula_error : public std::exception
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+public:
+ explicit formula_error(formula_error_t fe);
+ explicit formula_error(formula_error_t fe, std::string msg);
+ formula_error(formula_error&& other);
+
+ virtual ~formula_error();
+ virtual const char* what() const noexcept override;
+
+ formula_error_t get_error() const;
+};
+
+class IXION_DLLPUBLIC file_not_found : public general_error
+{
+public:
+ explicit file_not_found(const std::string& fpath);
+ virtual ~file_not_found() override;
+};
+
+class IXION_DLLPUBLIC formula_registration_error : public general_error
+{
+public:
+ explicit formula_registration_error(const std::string& msg);
+ virtual ~formula_registration_error() override;
+};
+
+/**
+ * This exception is thrown typically from the ixion::model_context class.
+ */
+class IXION_DLLPUBLIC model_context_error: public general_error
+{
+public:
+ enum error_type
+ {
+ circular_dependency,
+ invalid_named_expression,
+ sheet_name_conflict,
+ sheet_size_locked,
+ not_implemented
+ };
+
+ explicit model_context_error(const std::string& msg, error_type type);
+ virtual ~model_context_error() override;
+
+ error_type get_error_type() const;
+
+private:
+ error_type m_type;
+};
+
+class IXION_DLLPUBLIC not_implemented_error : public general_error
+{
+public:
+ explicit not_implemented_error(const std::string& msg);
+ virtual ~not_implemented_error() override;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/formula.hpp b/include/ixion/formula.hpp
new file mode 100644
index 0000000..f15c72d
--- /dev/null
+++ b/include/ixion/formula.hpp
@@ -0,0 +1,217 @@
+/* -*- 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_HPP
+#define INCLUDED_IXION_FORMULA_HPP
+
+#include "formula_tokens.hpp"
+#include "types.hpp"
+#include "env.hpp"
+
+#include <string>
+
+namespace ixion {
+
+class formula_cell;
+class formula_name_resolver;
+class model_context;
+
+/**
+ * Parse a raw formula expression string into formula tokens.
+ *
+ * @param cxt model context.
+ * @param pos address of the cell that has the formula expression.
+ * @param resolver name resolver object used to resolve name tokens.
+ * @param formula raw formula expression string to parse.
+ *
+ * @return formula tokens representing the parsed formula expression.
+ */
+IXION_DLLPUBLIC formula_tokens_t parse_formula_string(
+ model_context& cxt, const abs_address_t& pos,
+ const formula_name_resolver& resolver, std::string_view formula);
+
+/**
+ * Create a set of tokens that represent an invalid formula.
+ *
+ * This can be used for a cell containing an invalid formula expression, and
+ * the error information needs to be preserved.
+ *
+ * @param cxt model context.
+ * @param src_formula original formula string.
+ * @param error error string.
+ *
+ * @return a set of tokens, the first of which is a token of type fop_error,
+ * followed by two string tokens. The second token stores the
+ * original formula string, whereas the third one stores the error
+ * string. The first token stores the number of tokens that follows
+ * as its value of type std::size_t, which is always 2 in the current
+ * implementation.
+ */
+IXION_DLLPUBLIC formula_tokens_t create_formula_error_tokens(
+ model_context& cxt, std::string_view src_formula,
+ std::string_view error);
+
+/**
+ * Convert formula tokens into a human-readable string representation.
+ *
+ * @param cxt model context.
+ * @param pos address of the cell that has the formula tokens.
+ * @param resolver name resolver object used to print name tokens.
+ * @param tokens formula tokens.
+ *
+ * @return string representation of the formula tokens.
+ */
+IXION_DLLPUBLIC std::string print_formula_tokens(
+ const model_context& cxt, const abs_address_t& pos,
+ const formula_name_resolver& resolver, const formula_tokens_t& tokens);
+
+/**
+ * Convert formula tokens into a human-readable string representation.
+ *
+ * @param config Configuration options for printing preferences.
+ * @param cxt Model context.
+ * @param pos Address of the cell that has the formula tokens.
+ * @param resolver Name resolver object used to print name tokens.
+ * @param tokens Formula tokens to print.
+ *
+ * @return string representation of the formula tokens.
+ */
+IXION_DLLPUBLIC std::string print_formula_tokens(
+ const print_config& config, const model_context& cxt, const abs_address_t& pos,
+ const formula_name_resolver& resolver, const formula_tokens_t& tokens);
+
+/**
+ * Convert an individual formula token into a human-readable string
+ * representation.
+ *
+ * @param cxt model context.
+ * @param pos address of the cell that has the formula tokens.
+ * @param resolver name resolver object used to print name tokens.
+ * @param token formula token to convert.
+ *
+ * @return string representation of the formula token.
+ */
+IXION_DLLPUBLIC std::string print_formula_token(
+ const model_context& cxt, const abs_address_t& pos,
+ const formula_name_resolver& resolver, const formula_token& token);
+
+/**
+ * Convert an individual formula token into a human-readable string
+ * representation.
+ *
+ * @param config Configuration options for printing preferences.
+ * @param cxt Model context.
+ * @param pos Address of the cell that has the formula tokens.
+ * @param resolver Name resolver object used to print name tokens.
+ * @param token Formula token to convert.
+ *
+ * @return string representation of the formula token.
+ */
+IXION_DLLPUBLIC std::string print_formula_token(
+ const print_config& config, const model_context& cxt, const abs_address_t& pos,
+ const formula_name_resolver& resolver, const formula_token& token);
+
+/**
+ * Regisiter a formula cell with cell dependency tracker.
+ *
+ * @param cxt model context.
+ * @param pos address of the cell being registered. In case of grouped
+ * cells, the position must be that of teh top-left cell of that
+ * group.
+ * @param cell (optional) pointer to the formula cell object to register.
+ * You can skip this parameter, in which case the formula cell
+ * object will be fetched from the address of the cell. But
+ * passing a pointer will save the overhead of fetching.
+ */
+void IXION_DLLPUBLIC register_formula_cell(
+ model_context& cxt, const abs_address_t& pos, const formula_cell* cell = nullptr);
+
+/**
+ * Unregister a formula cell with cell dependency tracker if a formula cell
+ * exists at specified cell address. If there is no existing cell at the
+ * specified address, or the cell is not a formula cell, this function is a
+ * no-op.
+ *
+ * @param cxt model context.
+ * @param pos address of the cell being unregistered.
+ */
+void IXION_DLLPUBLIC unregister_formula_cell(
+ model_context& cxt, const abs_address_t& pos);
+
+/**
+ * Get the positions of those formula cells that directly or indirectly
+ * depend on the specified source cells.
+ *
+ * @param cxt model context.
+ * @param modified_cells collection of the postiions of cells that have been
+ * modified.
+ *
+ * @return collection of the positions of formula cells that directly or
+ * indirectly depend on at least one of the specified source cells.
+ */
+IXION_DLLPUBLIC abs_address_set_t query_dirty_cells(
+ model_context& cxt, const abs_address_set_t& modified_cells);
+
+/**
+ * Get a sequence of the positions of all formula cells that track at least
+ * one of the specified modified cells either directly or indirectly. Such
+ * formula cells are referred to as "dirty" formula cells. The sequence
+ * returned from this function is already sorted in topological order based
+ * on the dependency relationships between the affected formula cells. Note
+ * that if the model contains volatile formula cells, they will be included
+ * in the returned sequence each and every time.
+ *
+ * Use query_dirty_cells() instead if you don't need the results to be sorted
+ * in order of dependency, to avoid the extra overhead incurred by the
+ * sorting.
+ *
+ * @param cxt model context.
+ * @param modified_cells a collection of non-formula cells whose values have
+ * been updated. You can specify one or more ranges
+ * of cells rather than individual cell positions.
+ * @param dirty_formula_cells (optional) a collection of formula cells that
+ * are already known to be dirty. These formula
+ * cells will be added to the list of the
+ * affected formula cells returned from this
+ * function. Note that even though this
+ * parameter is a set of cell ranges, regular
+ * formula cell positions must be given as single
+ * cell addresses. Only the positions of grouped
+ * formula cells must be given as ranges.
+ *
+ * @return an sequence containing the positions of the formula cells that
+ * track at least one of the modified cells, as well as those
+ * formula cells that are already known to be dirty.
+ */
+IXION_DLLPUBLIC std::vector<abs_range_t> query_and_sort_dirty_cells(
+ model_context& cxt, const abs_range_set_t& modified_cells,
+ const abs_range_set_t* dirty_formula_cells = nullptr);
+
+/**
+ * Calculate all specified formula cells in the order they occur in the
+ * sequence.
+ *
+ * @param cxt model context.
+ * @param formula_cells formula cells to be calculated. The cells will be
+ * calculated in the order they appear in the sequence.
+ * In a typical use case, this will be the returned
+ * value from query_and_sort_dirty_cells.
+ * @param thread_count number of calculation threads to use. Note that
+ * passing 0 will make the process use the main thread
+ * only, while passing any number greater than 0 will
+ * make the process spawn specified number of
+ * calculation threads plus one additional thread to
+ * manage the calculation threads.
+ */
+void IXION_DLLPUBLIC calculate_sorted_cells(
+ model_context& cxt, const std::vector<abs_range_t>& formula_cells, size_t thread_count);
+
+} // namespace ixion
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/formula_function_opcode.hpp b/include/ixion/formula_function_opcode.hpp
new file mode 100644
index 0000000..ddfabc3
--- /dev/null
+++ b/include/ixion/formula_function_opcode.hpp
@@ -0,0 +1,370 @@
+/* -*- 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_FUNCTION_OPCODE_HPP
+#define INCLUDED_IXION_FORMULA_FUNCTION_OPCODE_HPP
+
+#include "env.hpp"
+
+#include <cstdint>
+#include <string_view>
+
+namespace ixion {
+
+/**
+ * Enum that represents built-in formula functions.
+ */
+enum class formula_function_t : uint16_t
+{
+ func_unknown = 0,
+ func_abs,
+ func_acos,
+ func_acosh,
+ func_acot,
+ func_acoth,
+ func_address,
+ func_aggregate,
+ func_and,
+ func_arabic,
+ func_areas,
+ func_asc,
+ func_asin,
+ func_asinh,
+ func_atan,
+ func_atan2,
+ func_atanh,
+ func_avedev,
+ func_average,
+ func_averagea,
+ func_averageif,
+ func_averageifs,
+ func_b,
+ func_bahttext,
+ func_base,
+ func_betadist,
+ func_betainv,
+ func_binomdist,
+ func_bitand,
+ func_bitlshift,
+ func_bitor,
+ func_bitrshift,
+ func_bitxor,
+ func_ceiling,
+ func_cell,
+ func_char,
+ func_chidist,
+ func_chiinv,
+ func_chisqdist,
+ func_chisqinv,
+ func_chitest,
+ func_choose,
+ func_clean,
+ func_code,
+ func_color,
+ func_column,
+ func_columns,
+ func_combin,
+ func_combina,
+ func_concat,
+ func_concatenate,
+ func_confidence,
+ func_correl,
+ func_cos,
+ func_cosh,
+ func_cot,
+ func_coth,
+ func_count,
+ func_counta,
+ func_countblank,
+ func_countif,
+ func_countifs,
+ func_covar,
+ func_critbinom,
+ func_csc,
+ func_csch,
+ func_cumipmt,
+ func_cumprinc,
+ func_current,
+ func_date,
+ func_datedif,
+ func_datevalue,
+ func_daverage,
+ func_day,
+ func_days,
+ func_days360,
+ func_db,
+ func_dcount,
+ func_dcounta,
+ func_ddb,
+ func_dde,
+ func_decimal,
+ func_degrees,
+ func_devsq,
+ func_dget,
+ func_dmax,
+ func_dmin,
+ func_dollar,
+ func_dproduct,
+ func_dstdev,
+ func_dstdevp,
+ func_dsum,
+ func_dvar,
+ func_dvarp,
+ func_eastersunday,
+ func_effect,
+ func_encodeurl,
+ func_errortype,
+ func_euroconvert,
+ func_even,
+ func_exact,
+ func_exp,
+ func_expondist,
+ func_fact,
+ func_false,
+ func_fdist,
+ func_filterxml,
+ func_find,
+ func_findb,
+ func_finv,
+ func_fisher,
+ func_fisherinv,
+ func_fixed,
+ func_floor,
+ func_forecast,
+ func_formula,
+ func_fourier,
+ func_frequency,
+ func_ftest,
+ func_fv,
+ func_gamma,
+ func_gammadist,
+ func_gammainv,
+ func_gammaln,
+ func_gauss,
+ func_gcd,
+ func_geomean,
+ func_getpivotdata,
+ func_goalseek,
+ func_growth,
+ func_harmean,
+ func_hlookup,
+ func_hour,
+ func_hyperlink,
+ func_hypgeomdist,
+ func_if,
+ func_iferror,
+ func_ifna,
+ func_ifs,
+ func_index,
+ func_indirect,
+ func_info,
+ func_int,
+ func_intercept,
+ func_ipmt,
+ func_irr,
+ func_isblank,
+ func_iserr,
+ func_iserror,
+ func_iseven,
+ func_isformula,
+ func_islogical,
+ func_isna,
+ func_isnontext,
+ func_isnumber,
+ func_isodd,
+ func_isoweeknum,
+ func_ispmt,
+ func_isref,
+ func_istext,
+ func_jis,
+ func_kurt,
+ func_large,
+ func_lcm,
+ func_left,
+ func_leftb,
+ func_len,
+ func_lenb,
+ func_linest,
+ func_ln,
+ func_log,
+ func_log10,
+ func_logest,
+ func_loginv,
+ func_lognormdist,
+ func_lookup,
+ func_lower,
+ func_match,
+ func_max,
+ func_maxa,
+ func_maxifs,
+ func_mdeterm,
+ func_median,
+ func_mid,
+ func_midb,
+ func_min,
+ func_mina,
+ func_minifs,
+ func_minute,
+ func_minverse,
+ func_mirr,
+ func_mmult,
+ func_mod,
+ func_mode,
+ func_month,
+ func_multirange,
+ func_munit,
+ func_mvalue,
+ func_n,
+ func_na,
+ func_neg,
+ func_negbinomdist,
+ func_networkdays,
+ func_nominal,
+ func_normdist,
+ func_norminv,
+ func_normsdist,
+ func_normsinv,
+ func_not,
+ func_now,
+ func_nper,
+ func_npv,
+ func_numbervalue,
+ func_odd,
+ func_offset,
+ func_or,
+ func_pduration,
+ func_pearson,
+ func_percentile,
+ func_percentrank,
+ func_permut,
+ func_permutationa,
+ func_phi,
+ func_pi,
+ func_pmt,
+ func_poisson,
+ func_power,
+ func_ppmt,
+ func_prob,
+ func_product,
+ func_proper,
+ func_pv,
+ func_quartile,
+ func_radians,
+ func_rand,
+ func_rank,
+ func_rate,
+ func_rawsubtract,
+ func_regex,
+ func_replace,
+ func_replaceb,
+ func_rept,
+ func_right,
+ func_rightb,
+ func_roman,
+ func_round,
+ func_rounddown,
+ func_roundsig,
+ func_roundup,
+ func_row,
+ func_rows,
+ func_rri,
+ func_rsq,
+ func_search,
+ func_searchb,
+ func_sec,
+ func_sech,
+ func_second,
+ func_sheet,
+ func_sheets,
+ func_sign,
+ func_sin,
+ func_sinh,
+ func_skew,
+ func_skewp,
+ func_sln,
+ func_slope,
+ func_small,
+ func_sqrt,
+ func_standardize,
+ func_stdev,
+ func_stdeva,
+ func_stdevp,
+ func_stdevpa,
+ func_steyx,
+ func_style,
+ func_substitute,
+ func_subtotal,
+ func_sum,
+ func_sumif,
+ func_sumifs,
+ func_sumproduct,
+ func_sumsq,
+ func_sumx2my2,
+ func_sumx2py2,
+ func_sumxmy2,
+ func_switch,
+ func_syd,
+ func_t,
+ func_tan,
+ func_tanh,
+ func_tdist,
+ func_text,
+ func_textjoin,
+ func_time,
+ func_timevalue,
+ func_tinv,
+ func_today,
+ func_transpose,
+ func_trend,
+ func_trim,
+ func_trimmean,
+ func_true,
+ func_trunc,
+ func_ttest,
+ func_type,
+ func_unichar,
+ func_unicode,
+ func_upper,
+ func_value,
+ func_var,
+ func_vara,
+ func_varp,
+ func_varpa,
+ func_vdb,
+ func_vlookup,
+ func_wait,
+ func_webservice,
+ func_weekday,
+ func_weeknum,
+ func_weibull,
+ func_xor,
+ func_year,
+ func_ztest,
+};
+
+/**
+ * Get a string representation of a formula function opcode.
+ *
+ * @param func formula function opcode.
+ *
+ * @return string representation of the opcode.
+ */
+IXION_DLLPUBLIC std::string_view get_formula_function_name(formula_function_t func);
+
+/**
+ * Get a formula function opcode from a formula function name.
+ *
+ * @param s formula function name.
+ *
+ * @return formula function opcode representing the specified name.
+ */
+IXION_DLLPUBLIC formula_function_t get_formula_function_opcode(std::string_view s);
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/formula_name_resolver.hpp b/include/ixion/formula_name_resolver.hpp
new file mode 100644
index 0000000..eb2a8a9
--- /dev/null
+++ b/include/ixion/formula_name_resolver.hpp
@@ -0,0 +1,129 @@
+/* -*- 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_NAME_RESOLVER_HPP
+#define INCLUDED_IXION_FORMULA_NAME_RESOLVER_HPP
+
+#include "address.hpp"
+#include "formula_function_opcode.hpp"
+
+#include <string>
+#include <memory>
+#include <variant>
+
+namespace ixion {
+
+class model_context;
+struct table_t;
+
+/**
+ * Structure that represents the type of a 'name' in a formula expression.
+ *
+ * A name can be either one of:
+ * <ul>
+ * <li>cell reference</li>
+ * <li>range reference</li>
+ * <li>table reference</li>
+ * <li>named expression</li>
+ * <li>function</li>
+ * </ul>
+ */
+struct IXION_DLLPUBLIC formula_name_t
+{
+ enum name_type
+ {
+ invalid = 0,
+ cell_reference,
+ range_reference,
+ table_reference,
+ named_expression,
+ function
+ };
+
+ /**
+ * Table information for a table reference name. Unlike the ixion::table_t
+ * counterpart, we store strings as string views as the resolver doesn't
+ * have access to the string pool.
+ */
+ struct table_type
+ {
+ std::string_view name;
+ std::string_view column_first;
+ std::string_view column_last;
+ table_areas_t areas;
+ };
+
+ using value_type = std::variant<address_t, range_t, table_type, formula_function_t>;
+
+ name_type type;
+ value_type value;
+
+ formula_name_t();
+
+ /**
+ * Return a string that represents the data stored internally. Useful for
+ * debugging.
+ */
+ std::string to_string() const;
+};
+
+/**
+ * Formula name resolvers resolves a name in a formula expression to a more
+ * concrete name type.
+ */
+class formula_name_resolver
+{
+public:
+ formula_name_resolver();
+ virtual ~formula_name_resolver() = 0;
+
+ /**
+ * Parse and resolve a reference string.
+ *
+ * @param s reference string to be parsed.
+ * @param pos base cell position, which influences the resolved reference
+ * position(s) containing relative address(es). When the
+ * reference string does not contain an explicit sheet name,
+ * the sheet address of the base cell position is used.
+ *
+ * @return result of the resovled reference.
+ */
+ virtual formula_name_t resolve(std::string_view s, const abs_address_t& pos) const = 0;
+ virtual std::string get_name(const address_t& addr, const abs_address_t& pos, bool sheet_name) const = 0;
+ virtual std::string get_name(const range_t& range, const abs_address_t& pos, bool sheet_name) const = 0;
+ virtual std::string get_name(const table_t& table) const = 0;
+
+ /**
+ * Given a numerical representation of column position, return its
+ * textural representation.
+ *
+ * @param col numerical column position.
+ *
+ * @return textural representation of column position.
+ */
+ virtual std::string get_column_name(col_t col) const = 0;
+
+ /**
+ * Create a formula name resolver instance according to the requested
+ * type.
+ *
+ * @param type type formula name resolver being requested.
+ * @param cxt document model context for resolving sheet names, or nullptr
+ * in case names being resolved don't contain sheet names.
+ *
+ * @return formula name resolver instance created on the heap. The caller
+ * is responsible for managing its life cycle.
+ */
+ IXION_DLLPUBLIC static std::unique_ptr<formula_name_resolver>
+ get(formula_name_resolver_t type, const model_context* cxt);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/formula_opcode.hpp b/include/ixion/formula_opcode.hpp
new file mode 100644
index 0000000..1f3d71b
--- /dev/null
+++ b/include/ixion/formula_opcode.hpp
@@ -0,0 +1,61 @@
+/* -*- 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_OPCODE_HPP
+#define INCLUDED_IXION_FORMULA_OPCODE_HPP
+
+namespace ixion {
+
+/** formula opcode type */
+enum fopcode_t
+{
+ fop_unknown = 0,
+
+ // data types
+ fop_single_ref,
+ fop_range_ref,
+ fop_table_ref,
+ fop_named_expression,
+ fop_string,
+ fop_value,
+ fop_function,
+
+ // arithmetic operators
+ fop_plus,
+ fop_minus,
+ fop_divide,
+ fop_multiply,
+ fop_exponent,
+
+ // string operators
+ fop_concat,
+
+ // relational operators
+ fop_equal,
+ fop_not_equal,
+ fop_less,
+ fop_greater,
+ fop_less_equal,
+ fop_greater_equal,
+
+ // parentheses, separators
+ fop_open,
+ fop_close,
+ fop_sep,
+ fop_array_row_sep,
+ fop_array_open,
+ fop_array_close,
+
+ // special conditions
+ fop_error, //< used to signify a special set of tokens representing formula cell with error.
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/formula_result.hpp b/include/ixion/formula_result.hpp
new file mode 100644
index 0000000..551af18
--- /dev/null
+++ b/include/ixion/formula_result.hpp
@@ -0,0 +1,136 @@
+/* -*- 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_RESULT_HPP
+#define INCLUDED_IXION_FORMULA_RESULT_HPP
+
+#include "global.hpp"
+
+#include <string>
+#include <memory>
+#include <iosfwd>
+
+namespace ixion {
+
+class matrix;
+class model_context;
+
+/**
+ * Store formula result which may be either numeric, textural, or error. In
+ * case the result is textural, it owns the instance of the string.
+ */
+class IXION_DLLPUBLIC formula_result
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+ enum class result_type { boolean, value, string, error, matrix };
+
+ formula_result();
+ formula_result(const formula_result& r);
+ formula_result(formula_result&& r);
+ formula_result(bool b);
+ formula_result(double v);
+ formula_result(std::string str);
+ formula_result(formula_error_t e);
+ formula_result(matrix mtx);
+ ~formula_result();
+
+ void reset();
+ void set_boolean(bool b);
+ void set_value(double v);
+ void set_string_value(std::string str);
+ void set_error(formula_error_t e);
+ void set_matrix(matrix mtx);
+
+ /**
+ * Get a boolean result value. The caller must make sure the result is of
+ * boolean type, else the behavior is undefined.
+ *
+ * @return boolean result value.
+ */
+ bool get_boolean() const;
+
+ /**
+ * Get a numeric result value. The caller must make sure the result is of
+ * numeric type, else the behavior is undefined.
+ *
+ * @return numeric result value.
+ */
+ double get_value() const;
+
+ /**
+ * Get a string value for textural result. The caller must make
+ * sure the result is of textural type, else the behavior is undefined.
+ *
+ * @return string value.
+ */
+ const std::string& get_string() const;
+
+ /**
+ * Get an error value of the result. The caller must make sure that the
+ * result is of error type, else the behavior is undefined.
+ *
+ * @return enum value representing the error.
+ * @see ixion::get_formula_error_name
+ */
+ 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 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.
+ */
+ matrix& get_matrix();
+
+ /**
+ * Get the type of result.
+ *
+ * @return enum value representing the result type.
+ */
+ result_type get_type() const;
+
+ /**
+ * Get a string representation of the result value no matter what the
+ * result type is.
+ *
+ * @param cxt model context object.
+ *
+ * @return string representation of the result value.
+ */
+ std::string str(const model_context& cxt) const;
+
+ /**
+ * Parse a textural representation of a formula result, and set result
+ * value of appropriate type.
+ *
+ * @param s formula result as a string.
+ */
+ void parse(std::string_view s);
+
+ formula_result& operator= (formula_result r);
+ bool operator== (const formula_result& r) const;
+ bool operator!= (const formula_result& r) const;
+};
+
+IXION_DLLPUBLIC std::ostream& operator<< (std::ostream& os, formula_result::result_type v);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/formula_tokens.hpp b/include/ixion/formula_tokens.hpp
new file mode 100644
index 0000000..d843dbd
--- /dev/null
+++ b/include/ixion/formula_tokens.hpp
@@ -0,0 +1,215 @@
+/* -*- 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_FORMULA_TOKENS_HPP
+#define INCLUDED_FORMULA_TOKENS_HPP
+
+#include "address.hpp"
+#include "table.hpp"
+#include "formula_opcode.hpp"
+#include "formula_function_opcode.hpp"
+#include "formula_tokens_fwd.hpp"
+
+#include <string>
+#include <variant>
+
+namespace ixion {
+
+/**
+ * Get a printable name for a formula opcode. The printable name is to be
+ * used only for informational purposes.
+ *
+ * @param oc formula opcode
+ *
+ * @return printable name for a formula opcode.
+ */
+IXION_DLLPUBLIC std::string_view get_opcode_name(fopcode_t oc);
+
+/**
+ * Get the string representation of a simple formula opcode. This function
+ * will return a non-empty string only for operator opcodes.
+ *
+ * @param oc formula opcode
+ *
+ * @return string representation of a formula opcode.
+ */
+IXION_DLLPUBLIC std::string_view get_formula_opcode_string(fopcode_t oc);
+
+/**
+ * Represents a single formula token.
+ */
+struct IXION_DLLPUBLIC formula_token final
+{
+ using value_type = std::variant<
+ address_t, range_t, table_t, formula_function_t,
+ double, string_id_t, std::string>;
+
+ /**
+ * Opcode that specifies the type of token. The value of this data member
+ * should <i>not</i> be modified after construction.
+ */
+ const fopcode_t opcode;
+
+ /**
+ * Value stored in the token. The type of this value varies depending on the
+ * token opcode value.
+ */
+ value_type value;
+
+ formula_token() = delete;
+
+ /**
+ * Constructor for opcode-only token.
+ *
+ * @param op formula opcode.
+ */
+ formula_token(fopcode_t op);
+
+ /**
+ * Constructor for a single-cell reference token. The opcode will be
+ * implicitly set to fop_single_ref.
+ *
+ * @param addr single-cell reference.
+ */
+ formula_token(const address_t& addr);
+
+ /**
+ * Constructor for a range reference token. The opcode will be
+ * implicitly set to fop_range_ref.
+ *
+ * @param range range reference.
+ */
+ formula_token(const range_t& range);
+
+ /**
+ * Constructor for a table reference token. The opcode will be implicitly
+ * set to fop_table_ref.
+ *
+ * @param table table reference.
+ */
+ formula_token(const table_t& table);
+
+ /**
+ * Constructor for a formula function token. The opcode will be implicitly
+ * set to fop_function.
+ *
+ * @param func function name enum value.
+ */
+ formula_token(formula_function_t func);
+
+ /**
+ * Constructor for a numeric value token. The opcode will be implicitly set
+ * to fop_value.
+ *
+ * @param v numeric value to be stored in the token.
+ */
+ formula_token(double v);
+
+ /**
+ * Constructor for a string value token. The opcode will be implicitly
+ * set to fop_string.
+ *
+ * @param sid string ID to be stored in the token.
+ */
+ formula_token(string_id_t sid);
+
+ /**
+ * Constructor for a named-expression token. The opcode will be implicitly
+ * set to fop_named_expression.
+ *
+ * @param name named expression to be stored in the token.
+ */
+ formula_token(std::string name);
+
+ /**
+ * Copy constructor.
+ */
+ formula_token(const formula_token& r);
+
+ /**
+ * Move constructor.
+ *
+ * @note This will be the same as the copy constructor if the stored value
+ * is not movable.
+ */
+ formula_token(formula_token&& r);
+
+ ~formula_token();
+
+ bool operator== (const formula_token& r) const;
+ bool operator!= (const formula_token& r) const;
+};
+
+/**
+ * Storage for a series of formula tokens.
+ */
+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();
+}
+
+/**
+ * Represents a named expression which stores a series of formula tokens.
+ */
+struct IXION_DLLPUBLIC named_expression_t
+{
+ /**
+ * Origin cell position which affects any relative references stored in
+ * the named expression.
+ */
+ abs_address_t origin;
+
+ /** Formula tokens. */
+ formula_tokens_t tokens;
+
+ named_expression_t();
+ named_expression_t(const abs_address_t& _origin, formula_tokens_t _tokens);
+ named_expression_t(const named_expression_t&) = delete;
+ named_expression_t(named_expression_t&& other);
+ ~named_expression_t();
+};
+
+IXION_DLLPUBLIC std::ostream& operator<< (std::ostream& os, const formula_token& ft);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/formula_tokens_fwd.hpp b/include/ixion/formula_tokens_fwd.hpp
new file mode 100644
index 0000000..4e8dd50
--- /dev/null
+++ b/include/ixion/formula_tokens_fwd.hpp
@@ -0,0 +1,27 @@
+/* -*- 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 {
+
+struct formula_token;
+class formula_tokens_store;
+using formula_tokens_store_ptr_t = boost::intrusive_ptr<formula_tokens_store>;
+using formula_tokens_t = std::vector<formula_token>;
+struct named_expression_t;
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/global.hpp b/include/ixion/global.hpp
new file mode 100644
index 0000000..4f8aa46
--- /dev/null
+++ b/include/ixion/global.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_GLOBAL_HPP
+#define INCLUDED_IXION_GLOBAL_HPP
+
+#include "types.hpp"
+#include "env.hpp"
+
+#include <memory>
+#include <string>
+
+namespace ixion {
+
+/**
+ * Get current time in seconds since epoch. Note that the value
+ * representing a time may differ from platform to platform. Use this
+ * value only to measure relative time.
+ *
+ * @return current time in seconds since epoch.
+ */
+IXION_DLLPUBLIC double get_current_time();
+
+IXION_DLLPUBLIC double to_double(std::string_view s);
+
+IXION_DLLPUBLIC bool to_bool(std::string_view s);
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/info.hpp b/include/ixion/info.hpp
new file mode 100644
index 0000000..1d7a41f
--- /dev/null
+++ b/include/ixion/info.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_INFO_HPP
+#define INCLUDED_IXION_INFO_HPP
+
+#include "env.hpp"
+
+namespace ixion {
+
+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
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/interface/Makefile.am b/include/ixion/interface/Makefile.am
new file mode 100644
index 0000000..8b3fdc3
--- /dev/null
+++ b/include/ixion/interface/Makefile.am
@@ -0,0 +1,6 @@
+
+libixiondir = $(includedir)/libixion-@IXION_API_VERSION@/ixion/interface
+
+libixion_HEADERS = \
+ session_handler.hpp \
+ table_handler.hpp
diff --git a/include/ixion/interface/Makefile.in b/include/ixion/interface/Makefile.in
new file mode 100644
index 0000000..f17c341
--- /dev/null
+++ b/include/ixion/interface/Makefile.in
@@ -0,0 +1,611 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = include/ixion/interface
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_17.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(libixion_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libixiondir)"
+HEADERS = $(libixion_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+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@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_CXX17 = @HAVE_CXX17@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+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@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MDDS_CFLAGS = @MDDS_CFLAGS@
+MDDS_LIBS = @MDDS_LIBS@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POW_LIB = @POW_LIB@
+PYTHON = @PYTHON@
+PYTHON_CFLAGS = @PYTHON_CFLAGS@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_LIBS = @PYTHON_LIBS@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+VULKAN_CFLAGS = @VULKAN_CFLAGS@
+VULKAN_LIBS = @VULKAN_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+libixiondir = $(includedir)/libixion-@IXION_API_VERSION@/ixion/interface
+libixion_HEADERS = \
+ session_handler.hpp \
+ table_handler.hpp
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/ixion/interface/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign include/ixion/interface/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-libixionHEADERS: $(libixion_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(libixion_HEADERS)'; test -n "$(libixiondir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libixiondir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libixiondir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libixiondir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libixiondir)" || exit $$?; \
+ done
+
+uninstall-libixionHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libixion_HEADERS)'; test -n "$(libixiondir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libixiondir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libixiondir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-libixionHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libixionHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ 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-libixionHEADERS \
+ 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-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-libixionHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/include/ixion/interface/session_handler.hpp b/include/ixion/interface/session_handler.hpp
new file mode 100644
index 0000000..7ed2a8e
--- /dev/null
+++ b/include/ixion/interface/session_handler.hpp
@@ -0,0 +1,50 @@
+/* -*- 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 __IXION_INTERFACE_SESSION_HANDLER_HPP__
+#define __IXION_INTERFACE_SESSION_HANDLER_HPP__
+
+#include "../formula_opcode.hpp"
+#include "../formula_function_opcode.hpp"
+#include "../env.hpp"
+
+#include <cstdlib>
+
+namespace ixion {
+
+class formula_cell;
+class formula_result;
+struct address_t;
+struct range_t;
+struct abs_address_t;
+struct table_t;
+
+namespace iface {
+
+class IXION_DLLPUBLIC session_handler
+{
+public:
+ virtual ~session_handler();
+
+ virtual void begin_cell_interpret(const abs_address_t& pos) = 0;
+ virtual void end_cell_interpret() = 0;
+ virtual void set_result(const formula_result& result) = 0;
+ virtual void set_invalid_expression(std::string_view msg) = 0;
+ virtual void set_formula_error(std::string_view msg) = 0;
+ virtual void push_token(fopcode_t fop) = 0;
+ virtual void push_value(double val) = 0;
+ virtual void push_string(size_t sid) = 0;
+ virtual void push_single_ref(const address_t& addr, const abs_address_t& pos) = 0;
+ virtual void push_range_ref(const range_t& range, const abs_address_t& pos) = 0;
+ virtual void push_table_ref(const table_t& table) = 0;
+ virtual void push_function(formula_function_t foc) = 0;
+};
+
+}}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/interface/table_handler.hpp b/include/ixion/interface/table_handler.hpp
new file mode 100644
index 0000000..0971d2e
--- /dev/null
+++ b/include/ixion/interface/table_handler.hpp
@@ -0,0 +1,63 @@
+/* -*- 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 IXION_INTERFACE_TABLE_HANDLER_HPP
+#define IXION_INTERFACE_TABLE_HANDLER_HPP
+
+#include "../types.hpp"
+
+namespace ixion {
+
+struct abs_address_t;
+struct abs_range_t;
+
+namespace iface {
+
+class IXION_DLLPUBLIC table_handler
+{
+public:
+ virtual ~table_handler();
+
+ /**
+ * Get the data range associated with a given column name. The current
+ * position is used to infer which table to use.
+ *
+ * @param pos current cell position.
+ * @param column_first name of the starting column within the table.
+ * @param column_last name of the ending column within the table, or
+ * empty_string_id if it's a single column.
+ * @param areas area specifiter value, which may consist of one or more
+ * values of table_area_t.
+ *
+ * @return referenced data range.
+ */
+ virtual abs_range_t get_range(
+ const abs_address_t& pos, string_id_t column_first, string_id_t column_last,
+ table_areas_t areas) const = 0;
+
+ /**
+ * Get the data range associated with given table and column names.
+ *
+ * @param table string identifier representing the table name.
+ * @param column_first name of the starting column within the table.
+ * @param column_last name of the ending column within the table, or
+ * empty_string_id if it's a single column.
+ * @param areas area specifiter value, which may consist of one or more
+ * values of table_area_t.
+ *
+ * @return referenced data range.
+ */
+ virtual abs_range_t get_range(
+ string_id_t table, string_id_t column_first, string_id_t column_last,
+ table_areas_t areas) const = 0;
+};
+
+}}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/macros.hpp b/include/ixion/macros.hpp
new file mode 100644
index 0000000..1ac84c1
--- /dev/null
+++ b/include/ixion/macros.hpp
@@ -0,0 +1,18 @@
+/* -*- 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 __IXION_MACROS_HPP__
+#define __IXION_MACROS_HPP__
+
+/**
+ * Use this macro with a literal string and it returns the literal string
+ * followed by its length.
+ */
+#define IXION_ASCII(literal) literal, sizeof(literal)-1
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/matrix.hpp b/include/ixion/matrix.hpp
new file mode 100644
index 0000000..d001f92
--- /dev/null
+++ b/include/ixion/matrix.hpp
@@ -0,0 +1,122 @@
+/* -*- 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_MATRIX_HPP
+#define INCLUDED_IXION_MATRIX_HPP
+
+#include "types.hpp"
+
+#include <memory>
+#include <vector>
+#include <string>
+#include <variant>
+
+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
+ * represent range values or in-line matrices.
+ */
+class IXION_DLLPUBLIC matrix
+{
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+public:
+
+ enum class element_type { numeric, string, boolean, error, empty };
+
+ struct element
+ {
+ using value_type = std::variant<double, bool, std::string_view, formula_error_t>;
+
+ element_type type;
+ value_type value;
+ };
+
+ matrix();
+ matrix(size_t rows, size_t cols);
+ matrix(size_t rows, size_t cols, double numeric);
+ matrix(size_t rows, size_t cols, bool boolean);
+ matrix(size_t rows, size_t cols, const std::string& str);
+ matrix(size_t rows, size_t cols, formula_error_t error);
+ 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 get_boolean(size_t row, size_t col) 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);
+ void set(size_t row, size_t col, bool val);
+ void set(size_t row, size_t col, const std::string& str);
+ void set(size_t row, size_t col, formula_error_t 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);
+
+ /**
+ * Constructor with initial values.
+ *
+ * @param array Array of initial values stored in column-major order.
+ * @param rows Number of rows.
+ * @param cols Number of columns.
+ */
+ 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;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/model_context.hpp b/include/ixion/model_context.hpp
new file mode 100644
index 0000000..b9d0987
--- /dev/null
+++ b/include/ixion/model_context.hpp
@@ -0,0 +1,446 @@
+/* -*- 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_MODEL_CONTEXT_HPP
+#define INCLUDED_IXION_MODEL_CONTEXT_HPP
+
+#include "env.hpp"
+#include "formula_tokens_fwd.hpp"
+#include "types.hpp"
+
+#include <string>
+#include <memory>
+#include <variant>
+
+namespace ixion {
+
+class cell_access;
+class dirty_cell_tracker;
+class formula_cell;
+class formula_name_resolver;
+class formula_result;
+class matrix;
+class model_iterator;
+class named_expressions_iterator;
+struct abs_address_t;
+struct abs_range_t;
+struct abs_rc_range_t;
+struct config;
+struct named_expression_t;
+
+namespace iface {
+
+class session_handler;
+class table_handler;
+
+}
+
+namespace detail {
+
+class model_context_impl;
+
+}
+
+/**
+ * This class stores all data relevant to current session. You can think of
+ * this like a document model for each formula calculation run. Note that
+ * only those methods called from the formula interpreter are specified in
+ * the interface; this explains why accessors for the most part only have
+ * the 'get' method not paired with its 'set' counterpart.
+ */
+class IXION_DLLPUBLIC model_context final
+{
+ friend class named_expressions_iterator;
+ friend class cell_access;
+
+ std::unique_ptr<detail::model_context_impl> mp_impl;
+
+public:
+ class IXION_DLLPUBLIC session_handler_factory
+ {
+ public:
+ virtual std::unique_ptr<iface::session_handler> create();
+ virtual ~session_handler_factory();
+ };
+
+ /**
+ * Cell value only to be used to input a collection of cells to sheet.
+ * Formula cells are not supported.
+ */
+ struct IXION_DLLPUBLIC input_cell
+ {
+ using value_type = std::variant<bool, double, std::string_view>;
+
+ celltype_t type;
+ value_type value;
+
+ /** Initializes the cell to be empty. */
+ input_cell(std::nullptr_t);
+ /** Boolean cell value. */
+ input_cell(bool b);
+ /** The char array must be null-terminated. */
+ input_cell(const char* s);
+ /** Numeric cell value. */
+ input_cell(double v);
+
+ input_cell(const input_cell& other);
+ };
+
+ class IXION_DLLPUBLIC input_row
+ {
+ std::initializer_list<input_cell> m_cells;
+ public:
+ input_row(std::initializer_list<input_cell> cells);
+
+ const std::initializer_list<input_cell>& cells() const;
+ };
+
+ model_context();
+ model_context(const rc_size_t& sheet_size);
+ ~model_context();
+
+ /**
+ * Query the current policy on what to do when a formula cell result is
+ * being requested while the result has not yet been computed.
+ */
+ formula_result_wait_policy_t get_formula_result_wait_policy() const;
+
+ /**
+ * This method is used to notify the model access implementer of formula
+ * events.
+ *
+ * @param event event type.
+ */
+ void notify(formula_event_t event);
+
+ const config& get_config() const;
+ dirty_cell_tracker& get_cell_tracker();
+ const dirty_cell_tracker& get_cell_tracker() const;
+
+ bool is_empty(const abs_address_t& addr) const;
+ bool is_empty(const abs_range_t& range) const;
+ celltype_t get_celltype(const abs_address_t& addr) const;
+ cell_value_t get_cell_value_type(const abs_address_t& addr) const;
+
+ /**
+ * Get a numeric representation of the cell value at specified position.
+ * If the cell at the specified position is a formula cell and its result
+ * has not yet been computed, it will block until the result becomes
+ * available.
+ *
+ * @param addr position of the cell.
+ *
+ * @return numeric representation of the cell value.
+ */
+ double get_numeric_value(const abs_address_t& addr) const;
+ bool get_boolean_value(const abs_address_t& addr) const;
+ string_id_t get_string_identifier(const abs_address_t& addr) const;
+
+ /**
+ * Get a string value associated with the cell at the specified position.
+ * It returns a valid string value only when the cell is a string cell, or
+ * is a formula cell containing a string result. Otherwise, it returns a
+ * nullptr.
+ *
+ * @param addr position of the cell.
+ *
+ * @return pointer to a string value if the cell stores a valid string
+ * value, else nullptr.
+ */
+ std::string_view get_string_value(const abs_address_t& addr) const;
+ const formula_cell* get_formula_cell(const abs_address_t& addr) const;
+ formula_cell* get_formula_cell(const abs_address_t& addr);
+
+ formula_result get_formula_result(const abs_address_t& addr) const;
+
+ /**
+ * Get a named expression token set associated with specified name if
+ * present. It first searches the local sheet scope for the name, then if
+ * it's not present, it searches the global scope.
+ *
+ * @param sheet index of the sheet scope to search in.
+ * @param name name of the expression.
+ *
+ * @return const pointer to the token set if exists, nullptr otherwise.
+ */
+ const named_expression_t* get_named_expression(sheet_t sheet, std::string_view name) const;
+
+ double count_range(const abs_range_t& range, values_t values_type) const;
+
+ /**
+ * Obtain range value in matrix form. Multi-sheet ranges are not
+ * supported. If the specified range consists of multiple sheets, it
+ * throws an exception.
+ *
+ * @param range absolute, single-sheet range address. Multi-sheet ranges
+ * are not allowed.
+ *
+ * @return range value represented as matrix.
+ */
+ matrix get_range_value(const abs_range_t& range) const;
+
+ /**
+ * Session handler instance receives various events from the formula
+ * interpretation run, in order to respond to those events. This is
+ * optional; the model context implementation is not required to provide a
+ * handler.
+ *
+ * @return a new session handler instance. It may be nullptr.
+ */
+ std::unique_ptr<iface::session_handler> create_session_handler();
+
+ /**
+ * Table interface provides access to all table ranges stored in the
+ * document model. A table is a 2-dimensional range of cells that include
+ * named columns. It is used when resolving a table reference that refers
+ * to a cell or a range of cells by the table name and/or column name.
+ *
+ * @return non-null pointer to the table storage inside the model, or
+ * nullptr if no table is present or supported by the model
+ * implementation.
+ */
+ iface::table_handler* get_table_handler();
+ const iface::table_handler* get_table_handler() const;
+
+ /**
+ * Try to add a new string to the string pool. If the same string already
+ * exists in the pool, the new string won't be added to the pool.
+ *
+ * @param s string to try to add to the pool.
+ *
+ * @return string_id_t integer value representing the string.
+ */
+ string_id_t add_string(std::string_view s);
+ const std::string* get_string(string_id_t identifier) const;
+
+ /**
+ * Get the index of sheet from sheet name. If the sheet name doesn't exist,
+ * it returns a value equal to <code>ixion::invalid_sheet</code>.
+ *
+ * @param name sheet name.
+ *
+ * @return 0-based sheet index, or <code>ixion::invalid_sheet</code> in case
+ * the document doesn't have a sheet by the specified name.
+ */
+ sheet_t get_sheet_index(std::string_view name) const;
+ std::string get_sheet_name(sheet_t sheet) const;
+
+ /**
+ * Set a new name to an existing sheet.
+ *
+ * @param sheet 0-based sheet index.
+ * @param name New name of a sheet.
+ */
+ void set_sheet_name(sheet_t sheet, std::string name);
+
+ /**
+ * Get the size of a sheet.
+ *
+ * @return sheet size.
+ */
+ rc_size_t get_sheet_size() const;
+
+ /**
+ * Return the number of sheets.
+ *
+ * @return number of sheets.
+ */
+ size_t get_sheet_count() const;
+
+ string_id_t append_string(std::string_view s);
+
+ void set_sheet_size(const rc_size_t& sheet_size);
+ void set_config(const config& cfg);
+
+ void empty_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, std::string_view s);
+ void set_string_cell(const abs_address_t& addr, string_id_t identifier);
+
+ cell_access get_cell_access(const abs_address_t& addr) const;
+
+ /**
+ * Duplicate the value of the source cell to one or more cells located
+ * immediately below it.
+ *
+ * @param src position of the source cell to copy the value from.
+ * @param n_dst number of cells below to copy the value to. It must be at
+ * least one.
+ */
+ void fill_down_cells(const abs_address_t& src, size_t n_dst);
+
+ /**
+ * 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.
+ *
+ * @return pointer to the formula cell instance inserted into the model.
+ */
+ formula_cell* 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.
+ *
+ * @return pointer to the formula cell instance inserted into the model.
+ */
+ formula_cell* set_formula_cell(const abs_address_t& addr, const formula_tokens_store_ptr_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.
+ * @param result cached result of this formula cell.
+ *
+ * @return pointer to the formula cell instance inserted into the model.
+ */
+ formula_cell* set_formula_cell(const abs_address_t& addr, const formula_tokens_store_ptr_t& tokens, formula_result result);
+
+ void set_grouped_formula_cells(const abs_range_t& group_range, formula_tokens_t tokens);
+
+ void set_grouped_formula_cells(const abs_range_t& group_range, formula_tokens_t tokens, formula_result result);
+
+ abs_range_t get_data_range(sheet_t sheet) const;
+
+ /**
+ * Set a named expression associated with a string name in the global
+ * scope.
+ *
+ * @param name name of the expression.
+ * @param expr formula tokens to use for the named expression.
+ */
+ void set_named_expression(std::string name, formula_tokens_t expr);
+
+ /**
+ * Set a named expression associated with a string name in the global
+ * scope.
+ *
+ * @param name name of the expression.
+ * @param origin position of the origin cell. Origin cell is relevant
+ * only when you need to convert the tokens into a string
+ * representation.
+ * @param expr formula tokens to use for the named expression.
+ */
+ void set_named_expression(std::string name, const abs_address_t& origin, formula_tokens_t expr);
+
+ /**
+ * Set a named expression associated with a string name in a sheet-local
+ * scope.
+ *
+ * @param sheet 0-based index of the sheet to register this expression
+ * with.
+ * @param name name of the expression.
+ * @param expr formula tokens to use for the named expression.
+ */
+ void set_named_expression(sheet_t sheet, std::string name, formula_tokens_t expr);
+
+ /**
+ * Set a named expression associated with a string name in a sheet-local
+ * scope.
+ *
+ * @param sheet 0-based index of the sheet to register this expression
+ * with.
+ * @param name name of the expression.
+ * @param origin position of the origin cell. Origin cell is relevant
+ * only when you need to convert the tokens into a string
+ * representation.
+ * @param expr formula tokens to use for the named expression.
+ */
+ void set_named_expression(sheet_t sheet, std::string name, const abs_address_t& origin, formula_tokens_t expr);
+
+ /**
+ * Append a new sheet to the model. The caller must ensure that the name
+ * of the new sheet is unique within the model context. When the name
+ * being used for the new sheet already exists, it throws a
+ * model_context_error exception.
+ *
+ * @param name name of the sheet to be inserted.
+ *
+ * @return sheet index of the inserted sheet.
+ *
+ * @throw model_context_error
+ */
+ sheet_t append_sheet(std::string name);
+
+ /**
+ * A convenient way to mass-insert a range of cell values. You can
+ * use a nested initializet list representing a range of cell values. The
+ * outer list represents rows.
+ *
+ * @param sheet sheet index.
+ * @param rows nested list of cell values. The outer list represents
+ * rows.
+ */
+ void set_cell_values(sheet_t sheet, std::initializer_list<input_row> rows);
+
+ void set_session_handler_factory(session_handler_factory* factory);
+
+ void set_table_handler(iface::table_handler* handler);
+
+ size_t get_string_count() const;
+
+ void dump_strings() const;
+
+ /**
+ * Get an integer string ID from a string value. If the string value
+ * doesn't exist in the pool, the value equal to empty_string_id gets
+ * returned.
+ *
+ * @param s string value.
+ *
+ * @return string_id_t integer string ID associated with the string value
+ * given.
+ */
+ string_id_t get_identifier_from_string(std::string_view s) const;
+
+ /**
+ * Get an immutable iterator that lets you iterate cell values in one
+ * sheet one at a time. <i>The caller has to ensure that the model
+ * content does not change for the duration of the iteration.</i>
+ *
+ * @param sheet sheet index.
+ * @param dir direction of the iteration.
+ * @param range range on the specified sheet to iterate over.
+ *
+ * @return model iterator instance.
+ */
+ model_iterator get_model_iterator(
+ sheet_t sheet, rc_direction_t dir, const abs_rc_range_t& range) const;
+
+ /**
+ * Get an iterator for global named expressions.
+ */
+ named_expressions_iterator get_named_expressions_iterator() const;
+
+ /**
+ * Get an interator for sheet-local named expressions.
+ *
+ * @param sheet 0-based index of the sheet where the named expressions are
+ * stored.
+ */
+ named_expressions_iterator get_named_expressions_iterator(sheet_t sheet) const;
+
+ void walk(
+ sheet_t sheet, const abs_rc_range_t& range, column_block_callback_t cb) const;
+
+ bool empty() const;
+};
+
+}
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/model_iterator.hpp b/include/ixion/model_iterator.hpp
new file mode 100644
index 0000000..dcebc8c
--- /dev/null
+++ b/include/ixion/model_iterator.hpp
@@ -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/.
+ */
+
+#ifndef INCLUDED_IXION_MODEL_ITERATOR_HPP
+#define INCLUDED_IXION_MODEL_ITERATOR_HPP
+
+#include "types.hpp"
+
+#include <memory>
+#include <iosfwd>
+#include <variant>
+
+namespace ixion {
+
+namespace detail { class model_context_impl; }
+class formula_cell;
+struct abs_rc_range_t;
+
+class IXION_DLLPUBLIC model_iterator
+{
+public:
+ class impl;
+
+private:
+ friend class detail::model_context_impl;
+ std::unique_ptr<model_iterator::impl> mp_impl;
+
+ model_iterator(const detail::model_context_impl& cxt, sheet_t sheet, const abs_rc_range_t& range, rc_direction_t dir);
+public:
+
+ struct IXION_DLLPUBLIC cell
+ {
+ using value_type = std::variant<bool, double, string_id_t, const formula_cell*>;
+
+ row_t row;
+ col_t col;
+ celltype_t type;
+ value_type value;
+
+ cell();
+ cell(row_t _row, col_t _col);
+ cell(row_t _row, col_t _col, bool _b);
+ cell(row_t _row, col_t _col, string_id_t _s);
+ cell(row_t _row, col_t _col, double _v);
+ cell(row_t _row, col_t _col, const formula_cell* _f);
+
+ bool operator== (const cell& other) const;
+ bool operator!= (const cell& other) const;
+ };
+
+ model_iterator();
+ model_iterator(const model_iterator&) = delete;
+ model_iterator(model_iterator&& other);
+ ~model_iterator();
+
+ model_iterator& operator= (const model_iterator&) = delete;
+ model_iterator& operator= (model_iterator&& other);
+
+ bool has() const;
+
+ void next();
+
+ const cell& get() const;
+};
+
+IXION_DLLPUBLIC std::ostream& operator<< (std::ostream& os, const model_iterator::cell& c);
+
+} // namespace ixion
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/module.hpp b/include/ixion/module.hpp
new file mode 100644
index 0000000..3f0fbc2
--- /dev/null
+++ b/include/ixion/module.hpp
@@ -0,0 +1,37 @@
+/* -*- 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 "env.hpp"
+
+namespace ixion { namespace draft {
+
+/**
+ * Initialize modules if exists.
+ */
+IXION_DLLPUBLIC void init_modules();
+
+IXION_DLLPUBLIC void unload_module(void* handler);
+
+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/named_expressions_iterator.hpp b/include/ixion/named_expressions_iterator.hpp
new file mode 100644
index 0000000..7511fef
--- /dev/null
+++ b/include/ixion/named_expressions_iterator.hpp
@@ -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/.
+ */
+
+#ifndef INCLUDED_IXION_NAMED_EXPRESSIONS_ITERATOR_HPP
+#define INCLUDED_IXION_NAMED_EXPRESSIONS_ITERATOR_HPP
+
+#include "types.hpp"
+#include "formula_tokens_fwd.hpp"
+
+#include <memory>
+#include <iosfwd>
+#include <string>
+
+namespace ixion {
+
+class model_context;
+struct abs_address_t;
+
+class IXION_DLLPUBLIC named_expressions_iterator
+{
+ friend class model_context;
+
+ struct impl;
+ std::unique_ptr<impl> mp_impl;
+
+ named_expressions_iterator(const model_context& cxt, sheet_t scope);
+
+public:
+ named_expressions_iterator();
+ named_expressions_iterator(const named_expressions_iterator& other);
+ named_expressions_iterator(named_expressions_iterator&& other);
+ ~named_expressions_iterator();
+
+ struct named_expression
+ {
+ const std::string* name;
+ const named_expression_t* expression;
+ };
+
+ size_t size() const;
+ bool has() const;
+ void next();
+
+ named_expression get() const;
+
+ named_expressions_iterator& operator= (const named_expressions_iterator& other);
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/table.hpp b/include/ixion/table.hpp
new file mode 100644
index 0000000..c0e556e
--- /dev/null
+++ b/include/ixion/table.hpp
@@ -0,0 +1,34 @@
+/* -*- 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_TABLE_HPP
+#define INCLUDED_IXION_TABLE_HPP
+
+#include "types.hpp"
+
+namespace ixion {
+
+struct IXION_DLLPUBLIC table_t
+{
+ string_id_t name;
+ string_id_t column_first;
+ string_id_t column_last;
+ table_areas_t areas;
+
+ table_t();
+
+ bool operator== (const table_t& r) const;
+ bool operator!= (const table_t& r) const;
+};
+
+IXION_DLLPUBLIC std::ostream& operator<<(std::ostream& os, const table_t& table);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/ixion/types.hpp b/include/ixion/types.hpp
new file mode 100644
index 0000000..5933646
--- /dev/null
+++ b/include/ixion/types.hpp
@@ -0,0 +1,373 @@
+/* -*- 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_TYPES_HPP
+#define INCLUDED_IXION_TYPES_HPP
+
+#include "env.hpp"
+
+#include <cstdlib>
+#include <cstdint>
+#include <string_view>
+#include <functional>
+
+namespace ixion {
+
+/** Column index type. */
+using col_t = int32_t;
+
+/** Row index type. */
+using row_t = int32_t;
+
+/** Sheet index type.*/
+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.
+ *
+ * All string values are converted into integer tokens. You need to call the
+ * get_string() method of ixion::model_context to get the
+ * actual string value.
+ */
+using string_id_t = uint32_t;
+
+/**
+ * Special sheet ID that represents a global scope, as opposed to a
+ * sheet-local scope.
+ */
+IXION_DLLPUBLIC_VAR const sheet_t global_scope;
+
+/**
+ * Special sheet ID that represents an invalid sheet.
+ */
+IXION_DLLPUBLIC_VAR const sheet_t invalid_sheet;
+
+/**
+ * Determine whether or not a given sheet index is valid.
+ *
+ * @param sheet sheet index to test.
+ *
+ * @return true if the sheet index is valid, false otherwise.
+ */
+IXION_DLLPUBLIC bool is_valid_sheet(sheet_t sheet);
+
+/** Global string ID representing an empty string. */
+IXION_DLLPUBLIC_VAR const string_id_t empty_string_id;
+
+/**
+ * This type represents a raw cell type as stored in ixion::model_context.
+ */
+enum class celltype_t : uint8_t
+{
+ /** unknown cell type.*/
+ unknown = 0,
+ /** cell contains a raw string value.*/
+ string,
+ /** cell contains a raw numeric value.*/
+ numeric,
+ /** cell contains a formula object. */
+ formula,
+ /** cell contains a raw boolean value. */
+ boolean,
+ /** cell is empty and contains absolutely nothing. */
+ empty
+};
+
+/**
+ * Similar to celltype_t, except that it does not include a formula type.
+ * Instead it uses the formula result type to classify its type. The error
+ * type refers to an error value in formula cell.
+ */
+enum class cell_value_t : uint8_t
+{
+ /** unknown cell value type. */
+ unknown = 0,
+ /**
+ * either the cell contains a raw string value, or a calculated formula
+ * cell whose result is of string type.
+ */
+ string,
+ /**
+ * either the cell contains a raw numeric value, or a calculated formula
+ * cell whose result is of numeric type.
+ */
+ numeric,
+ /**
+ * this type corresponds with a formula cell whose result contains an
+ * error.
+ */
+ error,
+ /**
+ * either the cell contains a raw boolean value type, or a calculated
+ * formula cell whose result is of boolean type.
+ */
+ boolean,
+ /**
+ * the cell is empty and contains nothing whatsoever.
+ */
+ empty
+};
+
+enum value_t
+{
+ value_none = 0x00,
+ value_string = 0x01,
+ value_numeric = 0x02,
+ value_boolean = 0x04,
+ value_empty = 0x08
+};
+
+/** type that stores a mixture of value_t values. */
+class values_t
+{
+ int m_val;
+public:
+ values_t(int val) : m_val(val) {}
+ bool is_numeric() const { return (m_val & value_numeric) == value_numeric; }
+ bool is_boolean() const { return (m_val & value_boolean) == value_boolean; }
+ bool is_string() const { return (m_val & value_string) == value_string; }
+ bool is_empty() const { return (m_val & value_empty) == value_empty; }
+};
+
+/** Value that specifies the area inside a table. */
+enum table_area_t
+{
+ table_area_none = 0x00,
+ table_area_data = 0x01,
+ table_area_headers = 0x02,
+ table_area_totals = 0x04,
+ table_area_all = 0x07
+};
+
+/** type that stores a mixture of ixion::table_area_t values. */
+using table_areas_t = int32_t;
+
+/**
+ * Formula name resolver type specifies how name tokens are resolved.
+ */
+enum class formula_name_resolver_t
+{
+ /** Unknown syntax. */
+ unknown = 0,
+ /** Default A1 syntax used in Excel */
+ excel_a1 = 1,
+ /** R1C1 syntax available in Excel */
+ excel_r1c1 = 2,
+ /** Default A1 syntax used in Calc */
+ calc_a1 = 3,
+ /** OpenFormula syntax */
+ odff = 4,
+ /** ODF cell-range-address syntax */
+ odf_cra = 5,
+};
+
+/**
+ * Formula error types. Note that only the official (i.e. non-internal)
+ * error types have their corresponding error strings. Use the
+ * get_formula_error_name() function to convert an enum member value of this
+ * type to its string representation.
+ */
+enum class formula_error_t : uint8_t
+{
+ no_error = 0,
+ ref_result_not_available = 1,
+ division_by_zero = 2,
+ invalid_expression = 3,
+ name_not_found = 4,
+ no_range_intersection = 5,
+ invalid_value_type = 6,
+ no_value_available = 7,
+
+ no_result_error = 253, // internal only error
+ stack_error = 254, // internal only error
+ general_error = 255, // internal only error
+};
+
+/**
+ * Type of policy on what to do when querying for the result of a formula
+ * cell whose result has not yet been calculated.
+ */
+enum class formula_result_wait_policy_t
+{
+ /**
+ * Querying for the result of a formula cell will block until the
+ * calculation is complete.
+ */
+ block_until_done,
+
+ /**
+ * Querying for the result of a formula cell that has not yet been
+ * calculated will throw an exception.
+ */
+ throw_exception,
+};
+
+/**
+ * Formula event type used for event notification during calculation of
+ * formula cells.
+ *
+ * @see ixion::model_context::notify
+ */
+enum class formula_event_t
+{
+ /** Start of the calculations of formula cells. */
+ calculation_begins,
+ /** End of the calculations of formula cells. */
+ calculation_ends,
+};
+
+/**
+ * Specifies iterator direction of a ixion::model_context.
+ */
+enum class rc_direction_t
+{
+ /** Flows left to right first then top to bottom. */
+ horizontal,
+ /** Flows top to bottom first then left to right. */
+ vertical
+};
+
+/**
+ * This structure stores a 2-dimensional size information.
+ */
+struct IXION_DLLPUBLIC rc_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 shares the same set of values.
+ */
+struct IXION_DLLPUBLIC formula_group_t
+{
+ /** Size of the formula group. */
+ rc_size_t size;
+ /**
+ * Unique value identifying the group a cell belongs to. Cells belonging
+ * to the same formula group should have the same value.
+ */
+ uintptr_t identity;
+ /** Boolean value indicating whether or not a cell is grouped. */
+ 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 null-terminated string representation of the formula error type.
+ */
+IXION_DLLPUBLIC std::string_view get_formula_error_name(formula_error_t fe);
+
+/**
+ * Parse a formula error string and convert it to a corresponding enum value.
+ *
+ * @param s string representation of a formula error type.
+ * @return enum value for a formula error type.
+ */
+IXION_DLLPUBLIC formula_error_t to_formula_error_type(std::string_view s);
+
+using column_block_handle = void*;
+
+/**
+ * Type of a column block that stores a series of adjacent cell values of the
+ * same type.
+ */
+enum class column_block_t : int
+{
+ unknown = 0,
+ empty,
+ boolean,
+ numeric,
+ string,
+ formula
+};
+
+/**
+ * Data that represents the shape of a column block.
+ */
+struct IXION_DLLPUBLIC column_block_shape_t
+{
+ std::size_t position;
+ std::size_t size;
+ std::size_t offset;
+ column_block_t type;
+ column_block_handle data;
+
+ column_block_shape_t();
+
+ column_block_shape_t(
+ std::size_t _position, std::size_t _size, std::size_t _offset,
+ column_block_t _type, column_block_handle _data);
+
+ column_block_shape_t(const column_block_shape_t& other);
+
+ column_block_shape_t& operator=(const column_block_shape_t& other);
+};
+
+/**
+ * Callback function type to be used during traversal of column data.
+ */
+using column_block_callback_t = std::function<bool(col_t, row_t, row_t, const column_block_shape_t&)>;
+
+IXION_DLLPUBLIC std::ostream& operator<< (std::ostream& os, const column_block_shape_t& v);
+
+/**
+ * Specifies how to determine whether or not to display a sheet name of a cell
+ * or range reference.
+ */
+enum class display_sheet_t
+{
+ /** Sheet name display preference is not specified. */
+ unspecified,
+ /** Sheet name should be always displayed. */
+ always,
+ /** Sheet name should never be displayed. */
+ never,
+ /**
+ * Sheet name should be displayed only when the sheet index of a reference
+ * is different from that of the position of a referencing cell.
+ */
+ only_if_different,
+};
+
+struct IXION_DLLPUBLIC print_config
+{
+ display_sheet_t display_sheet = display_sheet_t::only_if_different;
+
+ print_config();
+ print_config(const print_config& other);
+ ~print_config();
+};
+
+} // namespace ixion
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */