Interface

These are the SWIG interface files used to generate the Flibcpp modules.

flc

The primary file defines typemaps.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*!
 * \file flc.i
 *
 * Copyright (c) 2019-2020 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */

%module "flc"

#if defined(SWIGIMPORTED) && !defined(FLC_SWIGIMPORTED)
#error "To import the FLC module correctly, use ``%include \"import_flc.i\"``"
#endif

/* -------------------------------------------------------------------------
 * Header definition macros
 * ------------------------------------------------------------------------- */

%define %flc_add_header
%insert("fbegin") %{
! Flibcpp project, https://github.com/swig-fortran/flibcpp
! Copyright (c) 2019-2020 Oak Ridge National Laboratory, UT-Battelle, LLC.
! Distributed under an MIT open source license: see LICENSE for details.
%}
%insert("begin") %{
/*
 * Flibcpp project, https://github.com/swig-fortran/flibcpp
 * Copyright (c) 2019-2020 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */
%}
%enddef

%flc_add_header

/* -------------------------------------------------------------------------
 * Exception handling
 * ------------------------------------------------------------------------- */

// Rename the error variables' internal C symbols
#define SWIG_FORTRAN_ERROR_INT flc_ierr
#define SWIG_FORTRAN_ERROR_STR flc_get_serr

// Restore names in the wrapper code
%rename(ierr) flc_ierr;
%rename(get_serr) flc_get_serr;

// Unless we're directly building this module, delay exception handling
#ifndef SWIGIMPORTED
%include <exception.i>
#endif

/* -------------------------------------------------------------------------
 * Data types and instantiation
 * ------------------------------------------------------------------------- */

// Note: stdint.i inserts #include <stdint.h>
%include <stdint.i>

%define %flc_template_numeric(SRC, DST)
%template(DST) SRC<int32_t>;
%template(DST) SRC<int64_t>;
%template(DST) SRC<double>;
%enddef

/* -------------------------------------------------------------------------
 * Array view translation
 * ------------------------------------------------------------------------- */

%include <typemaps.i>
%apply (SWIGTYPE *DATA, size_t SIZE) {
       (int32_t  *DATA, size_t DATASIZE),
       (int64_t  *DATA, size_t DATASIZE),
       (double   *DATA, size_t DATASIZE),
       (void    **DATA, size_t DATASIZE)};

%apply (SWIGTYPE const *DATA, size_t SIZE) {
       (int32_t  const *DATA, size_t DATASIZE),
       (int64_t  const *DATA, size_t DATASIZE),
       (double   const *DATA, size_t DATASIZE),
       (void*    const *DATA, size_t DATASIZE)};

/* -------------------------------------------------------------------------
 * Version information
 * ------------------------------------------------------------------------- */

%apply char* { const char flibcpp_version[] };
%fortranbindc flibcpp_version_major;
%fortranbindc flibcpp_version_minor;
%fortranbindc flibcpp_version_patch;

// These symbols are defined in the CMake-generated `flibcpp_version.cpp`
%inline %{
extern "C" {
extern const char flibcpp_version[];
extern const int flibcpp_version_major;
extern const int flibcpp_version_minor;
extern const int flibcpp_version_patch;
}
%}

flc_algorithm

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/*!
 * \file flc_algorithm.i
 *
 * Copyright (c) 2019 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */

%module "flc_algorithm"
%include "import_flc.i"
%flc_add_header

%{
#include <algorithm>
#include <functional>
#include <numeric>
%}

/* -------------------------------------------------------------------------
 * Macros
 * ------------------------------------------------------------------------- */
%define %flc_cmp_algorithm(RETURN_TYPE, FUNCNAME, ARGS, CALL)

%inline {
// Operate using default "less than"
template<class T>
static RETURN_TYPE FUNCNAME(ARGS) {
  return FUNCNAME##_impl(CALL, std::less<T>());
}
// Operate using user-provided function pointer
template<class T>
static RETURN_TYPE FUNCNAME##_cmp(ARGS, bool (*cmp)(T, T)) {
  return FUNCNAME##_impl(CALL, cmp);
}
}

// Instantiate numeric overloads
%flc_template_numeric(FUNCNAME, FUNCNAME)
%flc_template_numeric(FUNCNAME##_cmp, FUNCNAME)

// Instantiate comparators with void* arguments
%template(FUNCNAME) FUNCNAME##_cmp<void*>;

%enddef

/* ------------------------------------------------------------------------- */
%define %flc_typemaps(NAME, TYPE...)

// Apply array conversion typemap
%apply (const SWIGTYPE *DATA, size_t SIZE) {
    (TYPE const *DATA1, size_t DATASIZE1),
    (TYPE const *DATA2, size_t DATASIZE2) };

// Explicitly declare function interface for callbacks
%fortrancallback("%s") flc_cmp_##NAME;
extern "C" bool flc_cmp_##NAME(TYPE left, TYPE right);

%enddef

/* -------------------------------------------------------------------------
 * Types
 * ------------------------------------------------------------------------- */

// Alias the native C integer to an "indexing" integer returned by algorithm
// functions.
%inline %{
typedef int index_int;
%}
%insert("fdecl") %{integer, parameter, public :: INDEX_INT = C_INT
%}

// Give it a particularly named type in the Fortran proxy code.
%apply int { index_int };
%typemap(ftype, in="integer(INDEX_INT), intent(in)") index_int
  %{integer(INDEX_INT)%}

// Apply array-to-C translation for numeric values
%apply (SWIGTYPE *DATA, size_t SIZE) { (index_int *IDX, size_t IDXSIZE) };

// Apply array and callback typemaps
%flc_typemaps(int4 , int32_t   )
%flc_typemaps(int8 , int64_t   )
%flc_typemaps(real8, double    )
%flc_typemaps(index, index_int )
%flc_typemaps(ptr  , void*     )

/* -------------------------------------------------------------------------
 * Sorting routines
 * ------------------------------------------------------------------------- */

%{
template<class T, class Compare>
static void sort_impl(T *data, size_t size, Compare cmp) {
    return std::sort(data, data + size, cmp);
}

template<class T, class Compare>
static bool is_sorted_impl(const T *data, size_t size, Compare cmp) {
    return std::is_sorted(data, data + size, cmp);
}

template<class T, class Compare>
static void argsort_impl(const T *data, size_t size,
                         index_int *index, size_t index_size,
                         Compare cmp) {
  // Fill invalid indices with zero
  if (size < index_size) {
    std::fill(index + size, index + index_size, 0);
  }
  size = std::min(size, index_size);
  // Fill the indices with 1 through size
  std::iota(index, index + size, 1);
  // Define a comparator that accesses the original data
  auto int_sort_cmp = [cmp, data](index_int left, index_int right)
  { return cmp(data[left - 1], data[right - 1]); };
  // Let the standard library do all the hard work!
  std::sort(index, index + size, int_sort_cmp);
}

%}

%flc_cmp_algorithm(void, sort,
                   %arg(T *DATA, size_t DATASIZE),
                   %arg(DATA, DATASIZE))
%flc_cmp_algorithm(bool, is_sorted,
                   %arg(const T *DATA, size_t DATASIZE),
                   %arg(DATA, DATASIZE))
%flc_cmp_algorithm(void, argsort,
                   %arg(const T *DATA, size_t DATASIZE,
                        index_int *IDX, size_t IDXSIZE),
                   %arg(DATA, DATASIZE, IDX, IDXSIZE))

/* -------------------------------------------------------------------------
 * Searching routines
 * ------------------------------------------------------------------------- */

%{
template<class T, class Compare>
static index_int binary_search_impl(const T *data, size_t size, T value,
                                    Compare cmp) {
  const T *end = data + size;
  auto iter = std::lower_bound(data, end, value, cmp);
  if (iter == end || cmp(*iter, value) || cmp(value, *iter))
    return 0;
  // Index of the found item *IN FORTAN INDEXING*
  return (iter - data) + 1;
}

template<class T, class Compare>
static void equal_range_impl(const T *data, size_t size, T value,
                             index_int &first_index, index_int &last_index,
                             Compare cmp) {
  const T *end = data + size;
  auto range_pair = std::equal_range(data, end, value, cmp);
  // Index of the min/max items *IN FORTAN INDEXING*
  first_index = range_pair.first - data + 1;
  last_index = range_pair.second - data;
}

template<class T, class Compare>
static void minmax_element_impl(const T *data, size_t size,
                                index_int &min_index, index_int &max_index,
                                Compare cmp) {
  const T *end = data + size;
  auto mm_pair = std::minmax_element(data, end, cmp);
  // Index of the min/max items *IN FORTAN INDEXING*
  min_index = mm_pair.first - data + 1;
  max_index = mm_pair.second - data + 1;
}
%}

%flc_cmp_algorithm(index_int, binary_search,
                   %arg(const T *DATA, size_t DATASIZE, T value),
                   %arg(DATA, DATASIZE, value))

%flc_cmp_algorithm(void, equal_range,
                   %arg(const T *DATA, size_t DATASIZE, T value,
                        index_int &first_index, index_int &last_index),
                   %arg(DATA, DATASIZE, value, first_index, last_index))

%flc_cmp_algorithm(void, minmax_element,
                   %arg(const T *DATA, size_t DATASIZE,
                        index_int &min_index, index_int &max_index),
                   %arg(DATA, DATASIZE, min_index, max_index))

/* -------------------------------------------------------------------------
 * Set operation routines
 * ------------------------------------------------------------------------- */

%{
template<class T, class Compare>
static bool includes_impl(const T *data1, size_t size1,
                          const T *data2, size_t size2,
                          Compare cmp) {
  return std::includes(data1, data1 + size1, data2, data2 + size2, cmp);
}
%}

%flc_cmp_algorithm(bool, includes,
                   %arg(const T *DATA1, size_t DATASIZE1,
                        const T *DATA2, size_t DATASIZE2),
                   %arg(DATA1, DATASIZE1, DATA2, DATASIZE2))

/* -------------------------------------------------------------------------
 * Modifying routines
 * ------------------------------------------------------------------------- */

%{
#include <random>
%}

%import "flc_random.i"

%inline {
template<class T>
static void shuffle(std::FLC_DEFAULT_ENGINE& g, T *DATA, size_t DATASIZE) {
    std::shuffle(DATA, DATA + DATASIZE, g);
}
}

%flc_template_numeric(shuffle, shuffle)
%template(shuffle) shuffle<void*>;

flc_chrono

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*!
 * \file flc_chrono.i
 *
 * Copyright (c) 2019 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */

%module "flc_chrono"
%include "import_flc.i"
%flc_add_header

/* -------------------------------------------------------------------------
 * Utility routines
 * ------------------------------------------------------------------------- */

%{
#include <chrono>
#include <thread>
#include <stdexcept>
%}

%inline %{
static void sleep_for(int ms) {
    if (ms < 0)
        throw std::domain_error("Invalid sleep time");
    std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}
%}

flc_random

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*!
 * \file flc_random.i
 *
 * Copyright (c) 2019 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */

%module "flc_random"
%include "import_flc.i"
%flc_add_header

%{
#include <random>
#if defined(_MSC_VER) && _MSC_VER < 1900
// Visual studio 2012's standard library lacks iterator constructors for
// std::discrete_distribution
#define FLC_MISSING_DISCRETE_ITER
#endif
%}

/* -------------------------------------------------------------------------
 * Macros
 * ------------------------------------------------------------------------- */

%define %flc_random_engine(NAME, GENERATOR, RESULT_TYPE)
namespace std {

%rename(NAME) GENERATOR;
%rename("next") GENERATOR::operator();

class GENERATOR
{
  public:
    typedef RESULT_TYPE result_type;

    GENERATOR();
    explicit GENERATOR(result_type seed_value);
    void seed(result_type seed_value);
    void discard(unsigned long long count);
    result_type operator()();
};

} // namespace std
%enddef

/* -------------------------------------------------------------------------
 * RNG distribution routines
 * ------------------------------------------------------------------------- */

%{
template<class D, class G, class T>
static inline void flc_generate(D dist, G& g, T* data, size_t size) {
  T* const end = data + size;
  while (data != end) {
    *data++ = dist(g);
  }
}
%}

%apply (const SWIGTYPE *DATA, size_t SIZE) {
       (const double *WEIGHTS, size_t WEIGHTSIZE) };

%inline %{
template<class T, class G>
static void uniform_int_distribution(T left, T right,
                                     G& engine, T* DATA, size_t DATASIZE) {
  flc_generate(std::uniform_int_distribution<T>(left, right),
               engine, DATA, DATASIZE);
}

template<class T, class G>
static void uniform_real_distribution(T left, T right,
                                      G& engine, T* DATA, size_t DATASIZE) {
  flc_generate(std::uniform_real_distribution<T>(left, right),
               engine, DATA, DATASIZE);
}

template<class T, class G>
static void normal_distribution(T mean, T stddev,
                                G& engine, T* DATA, size_t DATASIZE) {
  flc_generate(std::normal_distribution<T>(mean, stddev),
               engine, DATA, DATASIZE);
}

template<class T, class G>
static void discrete_distribution(const double* WEIGHTS, size_t WEIGHTSIZE,
                                  G& engine, T* DATA, size_t DATASIZE) {
#ifndef FLC_MISSING_DISCRETE_ITER
  std::discrete_distribution<T> dist(WEIGHTS, WEIGHTS + WEIGHTSIZE);
#else
  std::discrete_distribution<T> dist(
      std::initializer_list<double>(WEIGHTS, WEIGHTS + WEIGHTSIZE));
#endif
  T* const end = DATA + DATASIZE;
  while (DATA != end) {
    *DATA++ = dist(engine) + 1; // Note: transform to Fortran 1-offset
  }
}
%}

%define %flc_distribution(NAME, STDENGINE, TYPE)
%template(NAME##_distribution) NAME##_distribution< TYPE, std::STDENGINE >;
%enddef

// Engines
%flc_random_engine(MersenneEngine4, mt19937,    int32_t)
%flc_random_engine(MersenneEngine8, mt19937_64, int64_t)

#define FLC_DEFAULT_ENGINE mt19937
%flc_distribution(uniform_int,  FLC_DEFAULT_ENGINE, int32_t)
%flc_distribution(uniform_int,  FLC_DEFAULT_ENGINE, int64_t)
%flc_distribution(uniform_real, FLC_DEFAULT_ENGINE, double)

%flc_distribution(normal, FLC_DEFAULT_ENGINE, double)

// Discrete sampling distribution
%flc_distribution(discrete, FLC_DEFAULT_ENGINE, int32_t)
%flc_distribution(discrete, FLC_DEFAULT_ENGINE, int64_t)

flc_set

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*!
 * \file flc_set.i
 *
 * Copyright (c) 2019 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */

%module "flc_set"
%include "import_flc.i"
%flc_add_header

%include <std_set.i>

// Support for set operations
%{
#include <algorithm>
#include <iterator>
%}

/* -------------------------------------------------------------------------
 * Macro definitions
 * ------------------------------------------------------------------------- */

%define %flc_define_set_algorithm(FUNCNAME)
  %insert("header") {
  template<class Set_t>
  static Set_t flc_##FUNCNAME(const Set_t& left, const Set_t& right)
  {
      Set_t result;
      std::FUNCNAME(left.begin(), left.end(),
                    right.begin(), right.end(),
                    std::inserter(result, result.end()));
      return result;
  }
  } // end %insert
%enddef

%define %flc_extend_set_algorithm(FUNCNAME, RETVAL, TYPE)
  // The rename with the stringifying macro is necessary because 'union' is a
  // keyword.
  %rename(#FUNCNAME) std::set<TYPE>::set_##FUNCNAME;
  %extend std::set<TYPE> {
   RETVAL set_##FUNCNAME(const std::set<TYPE>& other)
   { return flc_set_##FUNCNAME(*$self, other); }
  } // end %extend
%enddef

%define %flc_std_set_extend_pod(CTYPE)
%extend {
  %apply (const SWIGTYPE *DATA, ::size_t SIZE)
    { (const CTYPE* DATA, size_type SIZE) };

  // Construct from an array of data
  set(const CTYPE* DATA, size_type SIZE) {
    return new std::set<CTYPE>(DATA, DATA + SIZE);
  }

  // Insert an array of data
  void insert(const CTYPE* DATA, size_type SIZE) {
    $self->insert(DATA, DATA + SIZE);
  }
}
%enddef

/* ------------------------------------------------------------------------- */
/*! \def %specialize_std_set_pod
 *
 * Inject member functions and typemaps for POD classes.
 *
 * These provide an efficient constructor from a Fortan array view.
 *
 * This definition is considered part of the \em public API so that downstream
 * apps that generate FLC-based bindings can instantiate their own POD sets.
 */
%define %specialize_std_set_pod(T)

namespace std {
  template<> class set<T> {
    %swig_std_set(T, std::less<T>, std::allocator<T>)
    %flc_std_set_extend_pod(T)
  };
}
%enddef

/* -------------------------------------------------------------------------
 * Algorithms
 * ------------------------------------------------------------------------- */

%flc_define_set_algorithm(set_difference)
%flc_define_set_algorithm(set_intersection)
%flc_define_set_algorithm(set_symmetric_difference)
%flc_define_set_algorithm(set_union)

%insert("header") %{
template<class Set_t>
static bool flc_set_includes(const Set_t& left, const Set_t& right)
{
    return std::includes(left.begin(), left.end(),
                         right.begin(), right.end());
}
%}

%define %flc_extend_algorithms(TYPE)
  %flc_extend_set_algorithm(difference, std::set<TYPE >, TYPE)
  %flc_extend_set_algorithm(intersection, std::set<TYPE >, TYPE)
  %flc_extend_set_algorithm(symmetric_difference, std::set<TYPE >, TYPE)
  %flc_extend_set_algorithm(union, std::set<TYPE >, TYPE)
  %flc_extend_set_algorithm(includes, bool, TYPE)
%enddef

/* -------------------------------------------------------------------------
 * Numeric sets
 * ------------------------------------------------------------------------- */

%flc_extend_algorithms(int)
%specialize_std_set_pod(int)

%template(SetInt) std::set<int>;

/* -------------------------------------------------------------------------
 * String sets
 * ------------------------------------------------------------------------- */

// Allow direct insertion of a wrapped std::string
%extend std::set<std::string> {
  %apply SWIGTYPE& { const std::string& STR_CLASS };

  void insert_ref(const std::string& STR_CLASS) {
    $self->insert(STR_CLASS);
  }
}

%include <std_string.i>
%import "flc_string.i"
%flc_extend_algorithms(std::string)
%template(SetString) std::set<std::string>;

flc_string

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*!
 * \file flc_string.i
 *
 * Copyright (c) 2019 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */

%module "flc_string"
%include "import_flc.i"
%flc_add_header

// SWIG always represents std::string as native strings. We load its typemaps
// but will explicitly create the class.
%include <std_string.i>

// Include typemaps for integer offsets and native integer types
%include <std_common.i>

/* -------------------------------------------------------------------------
 * Typemaps
 * ------------------------------------------------------------------------- */

// Typemap to convert positions from npos -> 0 and 1-offset otherwise. Similar
// to
%apply int FORTRAN_INT { size_t POSITION };
%typemap(out, noblock=1) size_t POSITION {
  $result = ($1 == std::string::npos ? 0 : $1 + 1);
}

/* -------------------------------------------------------------------------
 * String class definition
 * ------------------------------------------------------------------------- */

namespace std {
class string {
  public:
    // >>> TYPES
    typedef size_t size_type;
    typedef ptrdiff_t difference_type;
    typedef char value_type;
    typedef const char& const_reference;

    // Typemaps for making std::vector feel more like native Fortran:
    // - Use Fortran 1-offset indexing
    %apply int FORTRAN_INDEX {size_type pos,
                              size_type index,
                              size_type start_index,
                              size_type stop_index};
    // - Use native Fortran integers in proxy code
    %apply int FORTRAN_INT {size_type};

    // - Use fortran indexing (and 0 for not found) for search
    %apply size_t POSITION {size_type find};

    // - Allow access as an array view
    %apply SWIGTYPE& { string& view };
    %fortran_array_pointer(char, string& view);
    %typemap(out, noblock=1) string& view {
      $result.data = ($1->empty() ? NULL : const_cast<char*>($1->data()));
      $result.size = $1->size();
    }

    // - Allow interaction with other string objects
    %apply SWIGTYPE& {const string& OTHER};

  public:
    // >>> MEMBER FUNCTIONS

    string();
    string(size_type count, value_type ch);
    string(const std::string& s);

    // Accessors
    size_type size() const;
    bool empty() const;

    const_reference front() const;
    const_reference back() const;

    // Modify
    void resize(size_type count);
    void resize(size_type count, value_type v);
    void assign(const string& s);
    void push_back(value_type v);
    void pop_back();
    void clear();

    // String operations
    size_type find(const string& s, size_type pos = 0);
    void append(const string& s);
    int compare(const string& OTHER);

    // >>> EXTENSIONS

    %extend {
      %fragment("SWIG_check_range");

      void set(size_type index, value_type v) {
        SWIG_check_range(index, $self->size(),
                         "std::string::set",
                         return);
        (*$self)[index] = v;
      }

      value_type get(size_type index) {
        SWIG_check_range(index, $self->size(),
                         "std::string::get",
                         return $self->front());
        return (*$self)[index];
      }

      // Get a character array view
      string& view() { return *$self; }

      // Get a copy as a native Fortran string
      const string& str() { return *$self; }
    }
};

/* -------------------------------------------------------------------------
 * String conversion routines
 * ------------------------------------------------------------------------- */

%exception {
  SWIG_check_unhandled_exception();
  try {
    $action
  }
  catch (const std::invalid_argument& e) {
    SWIG_exception(SWIG_ValueError, e.what());
  }
  catch (const std::out_of_range& e) {
    SWIG_exception(SWIG_OverflowError, e.what());
  }
}

%fragment("<cctype>", "header") %{
#include <cctype>
%}

%fragment("flc_has_junk", "header",
          fragment="<cctype>", fragment="<algorithm>") %{
  SWIGINTERN bool flc_has_junk(const std::string& s, size_t pos) {
    return !std::all_of(s.begin() + pos, s.end(),
                        [](unsigned char c) -> bool { return std::isspace(c); });
  }
%}

%typemap(in, numinputs=0, noblock=1) size_t* result_pos (size_t temp_pos) {
  temp_pos = 0;
  $1 = &temp_pos;
}
%typemap(argout, noblock=1, fragment="flc_has_junk") size_t* result_pos {
  if (flc_has_junk(*arg1, temp_pos$argnum)) {
    SWIG_exception(SWIG_ValueError, "Junk at end of string");
  }
}

// String conversion routines
#define %add_string_int_conversion(RETURN_TYPE, NAME) \
  RETURN_TYPE NAME(const string& s, size_t* result_pos, int base = 10)
#define %add_string_real_conversion(RETURN_TYPE, NAME) \
  RETURN_TYPE NAME(const string& s, size_t* result_pos)

%add_string_int_conversion(int, stoi);
%add_string_int_conversion(long, stol);
%add_string_int_conversion(long long, stoll);
%add_string_real_conversion(float, stof);
%add_string_real_conversion(double, stod);

// Don't add exception code for subsequent functions
%exception;

} // namespace std

flc_vector

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*!
 * \file flc_vector.i
 *
 * Copyright (c) 2019-2020 Oak Ridge National Laboratory, UT-Battelle, LLC.
 * Distributed under an MIT open source license: see LICENSE for details.
 */

%module "flc_vector"
%include "import_flc.i"
%flc_add_header

%include <complex.i>
%include <std_vector.i>

/* -------------------------------------------------------------------------
 * Macro definitions
 * ------------------------------------------------------------------------- */

%define %flc_std_vector_extend_pod(CTYPE, IMTYPE)
%extend {
  %apply (const SWIGTYPE *DATA, ::size_t SIZE)
    { (const CTYPE* DATA, size_type SIZE) };

  // Construct from an array of data
  vector(const CTYPE* DATA, size_type SIZE) {
    return new std::vector<CTYPE>(DATA, DATA + SIZE);
  }

  // Assign from another vector
  void assign(const CTYPE* DATA, size_type SIZE) {
    $self->assign(DATA, DATA + SIZE);
  }

  // Get a mutable view to ourself
  %fortran_array_pointer(IMTYPE, vector<CTYPE>& view);

  %typemap(out, noblock=1) vector<CTYPE>& view {
    $result.data = ($1->empty() ? NULL : &(*$1->begin()));
    $result.size = $1->size();
  }

  vector<CTYPE>& view() {
    return *$self;
  }
}
%enddef

/* ------------------------------------------------------------------------- */
/*! \def %flc_template_std_vector_pod
 *
 * Inject member functions and typemaps for POD classes, and instantiate.
 *
 * The added methods provide an efficient constructor from a Fortan array view.
 * It also offers a "view" functionality for getting an array pointer to the
 * vector-owned data.
 *
 * This definition is considered part of the \em public API so that downstream
 * apps that generate FLC-based bindings can instantiate their own POD vectors.
 */
%define %flc_template_std_vector_pod(NAME, T)

namespace std {
  template<> class vector<T> {

    %swig_std_vector(T, const T&)
    %swig_std_vector_extend_ref(T)
    %flc_std_vector_extend_pod(T, T)
  };
}

// Instantiate the template
%template(NAME) std::vector<T>;

%enddef


/* ------------------------------------------------------------------------- */
/*! \def %flc_template_std_vector_complex
 *
 * Inject member functions and typemaps for std::complex instantiations.
 *
 * This definition is considered part of the \em public API so that downstream
 * apps that generate FLC-based bindings can instantiate their own POD vectors.
 */
%define %flc_template_std_vector_complex(NAME, T)

namespace std {
  template<> class vector<std::complex<T> > {

    %swig_std_vector(std::complex<T>, const std::complex<T>&)
    %swig_std_vector_extend_ref(std::complex<T>)
    %flc_std_vector_extend_pod(std::complex<T>, SwigComplex_##T)
  };
}

// Instantiate the template
%template(NAME) std::vector<std::complex<T> >;

%enddef

/* -------------------------------------------------------------------------
 * Numeric vectors
 * ------------------------------------------------------------------------- */

%flc_template_std_vector_pod(VectorInt4,  int32_t)
%flc_template_std_vector_pod(VectorInt8,  int64_t)
%flc_template_std_vector_pod(VectorReal8, double)

%flc_template_std_vector_complex(VectorComplex8, double)

/* -------------------------------------------------------------------------
 * String vectors
 * ------------------------------------------------------------------------- */

%include <std_string.i>
%import "flc_string.i"

%apply SWIGTYPE& { const std::string& value };

%extend std::vector<std::string> {
  void set_ref(size_type index, const std::string& value) {
    SWIG_check_range(index, $self->size(),
                     "std::vector<std::string>::set_ref",
                     return);
    (*$self)[index] = value;
  }
}

%template(VectorString) std::vector<std::string>;

%clear const std::string& value;