Octopus
namespace.F90
Go to the documentation of this file.
1!! Copyright (C) 2019 M. Oliveira, S. Ohlmann
2!!
3!! This Source Code Form is subject to the terms of the Mozilla Public
4!! License, v. 2.0. If a copy of the MPL was not distributed with this
5!! file, You can obtain one at https://mozilla.org/MPL/2.0/.
6!!
7
8#include "global.h"
9
10module namespace_oct_m
11 use global_oct_m
12 use mpi_oct_m
13 implicit none
14
15 private
16 public :: &
19
20 integer, parameter, public :: MAX_NAMESPACE_LEN = 128
21
22 type :: namespace_t
23 private
24 character(len=MAX_NAMESPACE_LEN) :: name = ""
25 type(namespace_t), pointer, public :: parent => null()
26 contains
27 procedure :: get => namespace_get
28 procedure :: len => namespace_len
29 generic :: operator(==) => equal
30 procedure :: equal => namespace_equal
31 procedure :: contains => namespace_contains
32 procedure :: is_contained_in => namespace_is_contained_in
33 end type namespace_t
34
35 interface namespace_t
36 procedure namespace_constructor
37 end interface namespace_t
38
39 type(namespace_t) :: global_namespace
40
41contains
42
43 !---------------------------------------------------------
48 recursive type(namespace_t) function namespace_constructor(name, parent, delimiter)
49 character(len=*), intent(in) :: name
50 type(namespace_t), optional, target, intent(in) :: parent
51 character(len=1), optional, intent(in) :: delimiter
52
53 integer :: total_len, parent_len
54 character(len=1) :: delimiter_
55
56 if (present(delimiter)) then
57 delimiter_ = delimiter
58 else
59 delimiter_ = '.'
60 end if
61
62 ! Calculate total length of namespace, including the parent
63 total_len = len_trim(name)
64 if (present(parent)) then
65 parent_len = parent%len()
66 if (parent_len > 0) then
67 total_len = total_len + parent_len + 1
68 end if
69 end if
70
71 ! If total length is too large, stop and explain the reason
72 if (total_len > max_namespace_len) then
73 write(stderr,'(a)') '*** Fatal Error (description follows)'
74 write(stderr,'(a)') 'Trying to create the following namespace:'
75 if (present(parent)) then
76 if (parent%len() > 0) then
77 write(stderr,'(a)') trim(parent%get()) // delimiter_ // name
78 end if
79 else
80 write(stderr,'(a)') name
81 end if
82 write(stderr,'(a,i4,a)') 'but namespaces are limited to ', max_namespace_len, ' characters'
83 call mpi_world%abort()
84 stop
85 end if
86
87 ! We do not allow the creation of empty namespaces, as that might lead to ambiguous paths
88 assert(len_trim(name) > 0)
89
90 namespace_constructor%name = name
91 if (present(parent)) then
92 namespace_constructor%parent => parent
93 else
94 nullify(namespace_constructor%parent)
95 end if
96
97 end function namespace_constructor
98
99 ! ---------------------------------------------------------
100 recursive function namespace_get(this, delimiter) result(name)
101 class(namespace_t), intent(in) :: this
102 character(len=1), optional, intent(in) :: delimiter
103 character(len=MAX_NAMESPACE_LEN) :: name
104
105 character(len=1) :: delimiter_
106
107 if (present(delimiter)) then
108 delimiter_ = delimiter
109 else
110 delimiter_ = '.'
111 end if
112
113 name = this%name
114 if (associated(this%parent)) then
115 if (len_trim(name) > 0 .and. this%parent%len() > 0) then
116 name = trim(this%parent%get(delimiter_)) // delimiter_ // trim(name)
117 end if
118 end if
119
120 end function namespace_get
122 ! ---------------------------------------------------------
123 pure recursive function namespace_len(this)
124 class(namespace_t), intent(in) :: this
125 integer :: namespace_len
126
127 integer :: parent_len
128
129 namespace_len = len_trim(this%name)
130 if (associated(this%parent)) then
131 parent_len = this%parent%len()
132 if (parent_len > 0) then
133 namespace_len = namespace_len + parent_len + 1
134 end if
135 end if
136
137 end function namespace_len
138
139 ! ---------------------------------------------------------
140 elemental logical function namespace_equal(lhs, rhs)
141 class(namespace_t), intent(in) :: lhs
142 class(namespace_t), intent(in) :: rhs
143
144 namespace_equal = lhs%name == rhs%name
145
146 end function namespace_equal
147
148 ! ---------------------------------------------------------
149 logical function namespace_contains(this, namespace)
150 class(namespace_t), target, intent(in) :: this
151 type(namespace_t), target, intent(in) :: namespace
152
153 logical :: found_ancestor
154 type(namespace_t), pointer :: this_ancestor, namespace_ancestor
155
156 ! Find if there is a common ancestor
157 found_ancestor = .false.
158 namespace_ancestor => namespace
159 do while (associated(namespace_ancestor))
160 found_ancestor = namespace_ancestor == this
161 if (found_ancestor) exit
162 namespace_ancestor => namespace_ancestor%parent
163 end do
164
165 if (found_ancestor) then
166 ! Check if the remaining ancestors are also equal
168 this_ancestor => this
169 do while (associated(namespace_ancestor%parent) .and. associated(this_ancestor%parent))
170 namespace_contains = namespace_ancestor%parent == this_ancestor%parent
171 if (.not. namespace_contains) exit
172 this_ancestor => this_ancestor%parent
173 namespace_ancestor => namespace_ancestor%parent
174 end do
175 else
176 ! We did not find a common ancestor
177 namespace_contains = .false.
178 end if
179
180 end function namespace_contains
181
182 ! ---------------------------------------------------------
183 logical function namespace_is_contained_in(this, name, delimiter) result(is_contained)
184 class(namespace_t), target, intent(in) :: this
185 character(len=*), intent(in) :: name
186 character(len=1), optional, intent(in) :: delimiter
187
188 integer :: si, se
189 character(len=1) :: delimiter_
190 type(namespace_t), target :: namespace
191 type(namespace_t), pointer :: next, parent
192
193 if (present(delimiter)) then
194 delimiter_ = delimiter
195 else
196 delimiter_ = '.'
197 end if
198
199 ! Create temporary namespace from name
200 si = index(name, delimiter_, back=.true.)
201 namespace%name = name(si+1:len(name))
202 next => namespace
203 do while (si /= 0)
204 se = si
205 si = index(name(:se-1), delimiter_, back=.true.)
206 allocate(next%parent)
207 next%parent = namespace_t(name(si+1:se-1), delimiter=delimiter)
208 next => next%parent
209 end do
210
211 ! Compare namespaces
212 is_contained = namespace%contains(this)
213
214 ! Deallocate all memory
215 parent => namespace%parent
216 do while (associated(parent))
217 next => parent%parent
218 deallocate(parent)
219 parent => next
220 end do
221
222 end function namespace_is_contained_in
223
224end module namespace_oct_m
225
226!! Local Variables:
227!! mode: f90
228!! coding: utf-8
229!! End:
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:262
logical function namespace_is_contained_in(this, name, delimiter)
Definition: namespace.F90:277
elemental logical function namespace_equal(lhs, rhs)
Definition: namespace.F90:234
recursive type(namespace_t) function namespace_constructor(name, parent, delimiter)
Create namespace from name. If parent is present, the new namespace will be a child of it....
Definition: namespace.F90:142
logical function namespace_contains(this, namespace)
Definition: namespace.F90:243
type(namespace_t), public global_namespace
Definition: namespace.F90:132
pure recursive integer function namespace_len(this)
Definition: namespace.F90:217
recursive character(len=max_namespace_len) function namespace_get(this, delimiter)
Definition: namespace.F90:194
int true(void)