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 ! ---------------------------------------------------------
101 !
102 recursive function namespace_get(this, delimiter) result(name)
103 class(namespace_t), intent(in) :: this
104 character(len=1), optional, intent(in) :: delimiter
105 character(len=MAX_NAMESPACE_LEN) :: name
106
107 character(len=1) :: delimiter_
108
109 if (present(delimiter)) then
110 delimiter_ = delimiter
111 else
112 delimiter_ = '.'
113 end if
114
115 name = this%name
116 if (associated(this%parent)) then
117 if (len_trim(name) > 0 .and. this%parent%len() > 0) then
118 name = trim(this%parent%get(delimiter_)) // delimiter_ // trim(name)
119 end if
120 end if
122 end function namespace_get
124 ! ---------------------------------------------------------
125 pure recursive function namespace_len(this)
126 class(namespace_t), intent(in) :: this
127 integer :: namespace_len
128
129 integer :: parent_len
130
131 namespace_len = len_trim(this%name)
132 if (associated(this%parent)) then
133 parent_len = this%parent%len()
134 if (parent_len > 0) then
135 namespace_len = namespace_len + parent_len + 1
136 end if
137 end if
138
139 end function namespace_len
140
141 ! ---------------------------------------------------------
142 elemental logical function namespace_equal(lhs, rhs)
143 class(namespace_t), intent(in) :: lhs
144 class(namespace_t), intent(in) :: rhs
145
146 namespace_equal = lhs%name == rhs%name
147
148 end function namespace_equal
149
150 ! ---------------------------------------------------------
151 logical function namespace_contains(this, namespace)
152 class(namespace_t), target, intent(in) :: this
153 type(namespace_t), target, intent(in) :: namespace
154
155 logical :: found_ancestor
156 type(namespace_t), pointer :: this_ancestor, namespace_ancestor
157
158 ! Find if there is a common ancestor
159 found_ancestor = .false.
160 namespace_ancestor => namespace
161 do while (associated(namespace_ancestor))
162 found_ancestor = namespace_ancestor == this
163 if (found_ancestor) exit
164 namespace_ancestor => namespace_ancestor%parent
165 end do
166
167 if (found_ancestor) then
168 ! Check if the remaining ancestors are also equal
170 this_ancestor => this
171 do while (associated(namespace_ancestor%parent) .and. associated(this_ancestor%parent))
172 namespace_contains = namespace_ancestor%parent == this_ancestor%parent
173 if (.not. namespace_contains) exit
174 this_ancestor => this_ancestor%parent
175 namespace_ancestor => namespace_ancestor%parent
176 end do
177 else
178 ! We did not find a common ancestor
179 namespace_contains = .false.
180 end if
181
182 end function namespace_contains
183
184 ! ---------------------------------------------------------
185 logical function namespace_is_contained_in(this, name, delimiter) result(is_contained)
186 class(namespace_t), target, intent(in) :: this
187 character(len=*), intent(in) :: name
188 character(len=1), optional, intent(in) :: delimiter
189
190 integer :: si, se
191 character(len=1) :: delimiter_
192 type(namespace_t), target :: namespace
193 type(namespace_t), pointer :: next, parent
194
195 if (present(delimiter)) then
196 delimiter_ = delimiter
197 else
198 delimiter_ = '.'
199 end if
200
201 ! Create temporary namespace from name
202 si = index(name, delimiter_, back=.true.)
203 namespace%name = name(si+1:len(name))
204 next => namespace
205 do while (si /= 0)
206 se = si
207 si = index(name(:se-1), delimiter_, back=.true.)
208 allocate(next%parent)
209 next%parent = namespace_t(name(si+1:se-1), delimiter=delimiter)
210 next => next%parent
211 end do
212
213 ! Compare namespaces
214 is_contained = namespace%contains(this)
215
216 ! Deallocate all memory
217 parent => namespace%parent
218 do while (associated(parent))
219 next => parent%parent
220 deallocate(parent)
221 parent => next
222 end do
223
224 end function namespace_is_contained_in
225
226end module namespace_oct_m
227
228!! Local Variables:
229!! mode: f90
230!! coding: utf-8
231!! End:
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:266
logical function namespace_is_contained_in(this, name, delimiter)
Definition: namespace.F90:279
elemental logical function namespace_equal(lhs, rhs)
Definition: namespace.F90:236
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:245
type(namespace_t), public global_namespace
Definition: namespace.F90:132
pure recursive integer function namespace_len(this)
Definition: namespace.F90:219
recursive character(len=max_namespace_len) function namespace_get(this, delimiter)
get full name, including parents
Definition: namespace.F90:196
int true(void)