Skip to content

Commit ebd1f22

Browse files
committed
Add std::string support
1 parent be2f408 commit ebd1f22

File tree

11 files changed

+2042
-4
lines changed

11 files changed

+2042
-4
lines changed

CMakeLists.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,16 @@ endfunction()
165165

166166
# Four SWIG libraries
167167
swig_fortran_add_module(flc "${FLIBCPP_VERSION_CPP}")
168-
swig_fortran_add_module(flc_random)
169-
target_link_libraries(flc_random flc)
168+
170169
swig_fortran_add_module(flc_algorithm)
171170
target_link_libraries(flc_algorithm flc_random flc)
171+
172+
swig_fortran_add_module(flc_random)
173+
target_link_libraries(flc_random flc)
174+
175+
swig_fortran_add_module(flc_string)
176+
target_link_libraries(flc_string flc)
177+
172178
swig_fortran_add_module(flc_vector)
173179
target_link_libraries(flc_vector flc)
174180

doc/interface.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ flc_random
3636
.. literalinclude:: ../src/flc_random.i
3737
:linenos:
3838

39+
flc_string
40+
=============
41+
42+
.. literalinclude:: ../src/flc_string.i
43+
:linenos:
44+
3945
flc_vector
4046
=============
4147

doc/modules/algorithm.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ zero.
7272

7373
.. _argsort: https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.argsort.html
7474

75+
.. _modules_algorithm_searching:
76+
7577
Searching
7678
=========
7779

doc/modules/string.rst

Lines changed: 133 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,139 @@
88
String
99
******
1010

11-
String manipulation is not yet implemented.
11+
The string module includes the ``String`` derived type and a handful of string
12+
conversion functions.
13+
14+
String type
15+
===========
16+
17+
The C++ standard library "string" is a dynamically resizable, mutable character
18+
array.
19+
20+
Construction and destruction
21+
----------------------------
22+
23+
Strings are constructed using three interface functions:
24+
25+
- The function without arguments creates an empty string;
26+
- An integer argument ``count`` and a single character will create a string
27+
of size ``count`` filled with that character; and
28+
- A standard Fortran ``character(kind=C_CHAR, len=*)`` which will be copied
29+
to the string.
30+
31+
Here are three examples of initialization::
32+
33+
use flc_string, only : String
34+
type(String) :: v
35+
36+
s = String()
37+
! s%size() == 0
38+
s = String(10, "!")
39+
! s%size() == 10
40+
! s%get(i) == "!"
41+
s = String("I am a string!")
42+
43+
Modification
44+
------------
45+
46+
Like :ref:`vectors <modules_Vector>`, Strings can be resized dynamically using
47+
a variety of methods:
48+
49+
- ``resize`` to specify an exact size;
50+
- ``push_back`` to add a new character to the end of it;
51+
- ``append`` to add another string to the end
52+
- ``pop_back`` to remove the last character;
53+
- ``clear`` to remove all elements.
54+
55+
The string also has a ``set`` bound subroutine for assigning a character to a
56+
specified index::
57+
58+
type(String) :: s
59+
60+
s = String("=", 10)
61+
call s%set(1, "8")
62+
call s%set(s%size(), "D")
63+
64+
.. important:: Unlike the C++ version of this class, **strings in Flibcpp
65+
use 1-offset indexing**. This means that ``s%get(1)`` is the same as the C++
66+
``s[0]``: it returns the first element (i.e. the element with an offset of
67+
zero).
68+
69+
Access
70+
------
71+
72+
The size of a string is returned by the bound function ``size``; ``get``
73+
returns the character at an index; and ``front`` and ``back`` are aliases for
74+
``get(1)`` and ``get(v%size())``, respectively.
75+
76+
Search
77+
------
78+
79+
The ``find`` bound function will search for a substring, starting at an
80+
optional position. Like the :ref:`search
81+
algorithms <modules_algorithm_searching>` in Flibcpp, a search result of `0`
82+
indicates "not found" and any other result is the 1-offset index in the
83+
string. ::
84+
85+
type(String) :: s
86+
integer :: i
87+
88+
s = String("meowmeow")
89+
i = s%find("meow") ! Returns 1
90+
i = s%find("meow", 3) ! Returns 5
91+
i = s%find("woof") ! Returns 0
92+
93+
View as an array pointer
94+
------------------------
95+
96+
The string can be viewed (and indeed modified) as an array of character
97+
elements::
98+
99+
type(String) :: s
100+
character, dimension(:), pointer :: charptr
101+
102+
s = String("Hello!")
103+
charptr => s%view()
104+
charptr(6) = "?" ! change greeting to a question
105+
106+
Conversion to native string
107+
---------------------------
108+
109+
The ``str`` type-bound function returns an allocated character string::
110+
111+
character(len=:), allocatable :: native
112+
type(String) :: s
113+
114+
s = String("Hello world")
115+
native = s%str()
116+
write(0,"(a)") native
117+
118+
119+
Conversion functions
120+
====================
121+
122+
The ``flc_string`` module includes several module procedures for converting
123+
native Fortran strings to integers and real numbers. These functions are robust
124+
and exception-safe, allowing intelligent error handling from the Fortran side.
125+
126+
- Integer conversion: ``stoi``, ``stol``, ``stoll``
127+
- Real conversion: ``stof``, ``stod``
128+
129+
::
130+
131+
use flc, only : ierr, get_serr, SWIG_OverflowError, SWIG_ValueError
132+
use flc_string
133+
implicit none
134+
integer(4) :: temp
135+
character(len=100) :: tempstr
136+
137+
read(*, '(a)') tempstr
138+
temp = stoi(trim(tempstr))
139+
if (ierr == SWIG_OverflowError) then
140+
write(0,*) "Your integer is too darn big!"
141+
elseif (ierr == SWIG_ValueError) then
142+
write(0,*) "That thing you entered? It wasn't an integer."
143+
end if
12144

13145
.. ############################################################################
14146
.. end of doc/modules/string.rst

doc/modules/vector.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ the end of the vector (increasing the size by one) with ``push_back``. The
5252
removes a specific vector index or range of indices. ``clear`` removes
5353
all elements. Finally, ``set`` sets the value of an element at a given index.
5454

55-
.. important:: Unlike the C++ version of this class, **all vectors in flibcpp
55+
.. important:: Unlike the C++ version of this class, **all vectors in Flibcpp
5656
use 1-offset indexing**. This means that ``v%get(1)`` is the same as the C++
5757
``v[0]``: it returns the first element (i.e. the element with an offset of
5858
zero).

src/flc_string.i

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*!
2+
* \file flc_string.i
3+
*
4+
* Copyright (c) 2019 Oak Ridge National Laboratory, UT-Battelle, LLC.
5+
* Distributed under an MIT open source license: see LICENSE for details.
6+
*/
7+
8+
%module "flc_string"
9+
%include "import_flc.i"
10+
11+
// SWIG always represents std::string as native strings. We load its typemaps
12+
// but will explicitly create the class.
13+
%include <std_string.i>
14+
15+
// Include typemaps for integer offsets and native integer types
16+
%include <std_common.i>
17+
18+
// Typemap to convert positions from npos -> 0 and 1-offset otherwise
19+
%apply int FORTRAN_INT { std::size_t POSITION };
20+
%typemap(out, noblock=1) std::size_t POSITION {
21+
$result = ($1 == std::string::npos ? 0 : $1 + 1);
22+
}
23+
24+
namespace std {
25+
class string {
26+
public:
27+
// >>> TYPES
28+
typedef size_t size_type;
29+
typedef ptrdiff_t difference_type;
30+
typedef char value_type;
31+
typedef const char& const_reference;
32+
33+
// Typemaps for making std::vector feel more like native Fortran:
34+
// - Use Fortran 1-offset indexing
35+
%apply int FORTRAN_INDEX {size_type pos,
36+
size_type index,
37+
size_type start_index,
38+
size_type stop_index};
39+
// - Use native Fortran integers in proxy code
40+
%apply int FORTRAN_INT {size_type};
41+
42+
// - Use fortran indexing (and 0 for not found) for search
43+
%apply std::size_t POSITION {size_type find};
44+
45+
// - Allow access as an array view
46+
%apply SWIGTYPE& { string& view };
47+
%fortran_array_pointer(char, string& view);
48+
%typemap(out, noblock=1) string& view {
49+
$result.data = ($1->empty() ? NULL : const_cast<char*>($1->data()));
50+
$result.size = $1->size();
51+
}
52+
53+
// - Allow interaction with other string objects
54+
%apply SWIGTYPE& {const string& OTHER};
55+
56+
public:
57+
// >>> MEMBER FUNCTIONS
58+
59+
// TODO: add more constructors
60+
string();
61+
string(size_type count, value_type ch);
62+
string(const std::string& s);
63+
64+
// Accessors
65+
size_type size() const;
66+
bool empty() const;
67+
68+
const_reference front() const;
69+
const_reference back() const;
70+
71+
// Modify
72+
void resize(size_type count);
73+
void resize(size_type count, value_type v);
74+
void assign(const string& s);
75+
void push_back(value_type v);
76+
void pop_back();
77+
void clear();
78+
79+
// String operations
80+
size_type find(const string& s, size_type pos = 0);
81+
void append(const string& s);
82+
int compare(const string& OTHER);
83+
84+
// >>> EXTENSIONS
85+
// (TODO: add the same erase/insert extensions as std::vector)
86+
87+
%extend {
88+
%fragment("SWIG_check_range");
89+
90+
void set(size_type index, value_type v) {
91+
SWIG_check_range(index, $self->size(),
92+
"std::string::set",
93+
return);
94+
(*$self)[index] = v;
95+
}
96+
97+
value_type get(size_type index) {
98+
SWIG_check_range(index, $self->size(),
99+
"std::string::get",
100+
return $self->front());
101+
return (*$self)[index];
102+
}
103+
104+
// Get a character array view
105+
string& view() { return *$self; }
106+
107+
// Get a copy as a native Fortran string
108+
const string& str() { return *$self; }
109+
}
110+
};
111+
112+
%exception {
113+
SWIG_check_unhandled_exception();
114+
try {
115+
$action
116+
}
117+
catch (const std::invalid_argument& e) {
118+
SWIG_exception(SWIG_ValueError, e.what());
119+
}
120+
catch (const std::out_of_range& e) {
121+
SWIG_exception(SWIG_OverflowError, e.what());
122+
}
123+
}
124+
125+
// String conversion
126+
int stoi(const std::string& s);
127+
long stol(const std::string& s);
128+
long long stoll(const std::string& s);
129+
float stof(const std::string& s);
130+
double stod(const std::string& s);
131+
132+
} // namespace std

src/generated/flc.f90

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ module flc
2121
integer(C_SIZE_T), public :: size = 0
2222
end type
2323
public :: get_serr
24+
integer(C_INT), parameter, public :: SWIG_UnknownError = -1_C_INT
25+
integer(C_INT), parameter, public :: SWIG_IOError = -2_C_INT
26+
integer(C_INT), parameter, public :: SWIG_RuntimeError = -3_C_INT
27+
integer(C_INT), parameter, public :: SWIG_IndexError = -4_C_INT
28+
integer(C_INT), parameter, public :: SWIG_TypeError = -5_C_INT
29+
integer(C_INT), parameter, public :: SWIG_DivisionByZero = -6_C_INT
30+
integer(C_INT), parameter, public :: SWIG_OverflowError = -7_C_INT
31+
integer(C_INT), parameter, public :: SWIG_SyntaxError = -8_C_INT
32+
integer(C_INT), parameter, public :: SWIG_ValueError = -9_C_INT
33+
integer(C_INT), parameter, public :: SWIG_SystemError = -10_C_INT
34+
integer(C_INT), parameter, public :: SWIG_AttributeError = -11_C_INT
35+
integer(C_INT), parameter, public :: SWIG_MemoryError = -12_C_INT
36+
integer(C_INT), parameter, public :: SWIG_NullReferenceError = -13_C_INT
2437
public :: get_flibcpp_version
2538
integer(C_INT), protected, public, &
2639
bind(C, name="flibcpp_version_major") :: flibcpp_version_major

0 commit comments

Comments
 (0)