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 procedure :: get_hash32 => namespace_get_hash32
34 end type namespace_t
35
36 interface namespace_t
37 procedure namespace_constructor
38 end interface namespace_t
39
40 type(namespace_t) :: global_namespace
41
42contains
43
44 !---------------------------------------------------------
49 recursive type(namespace_t) function namespace_constructor(name, parent, delimiter)
50 character(len=*), intent(in) :: name
51 type(namespace_t), optional, target, intent(in) :: parent
52 character(len=1), optional, intent(in) :: delimiter
53
54 integer :: total_len, parent_len
55 character(len=1) :: delimiter_
56
57 if (present(delimiter)) then
58 delimiter_ = delimiter
59 else
60 delimiter_ = '.'
61 end if
62
63 ! Calculate total length of namespace, including the parent
64 total_len = len_trim(name)
65 if (present(parent)) then
66 parent_len = parent%len()
67 if (parent_len > 0) then
68 total_len = total_len + parent_len + 1
69 end if
70 end if
71
72 ! If total length is too large, stop and explain the reason
73 if (total_len > max_namespace_len) then
74 write(stderr,'(a)') '*** Fatal Error (description follows)'
75 write(stderr,'(a)') 'Trying to create the following namespace:'
76 if (present(parent)) then
77 if (parent%len() > 0) then
78 write(stderr,'(a)') trim(parent%get()) // delimiter_ // name
79 end if
80 else
81 write(stderr,'(a)') name
82 end if
83 write(stderr,'(a,i4,a)') 'but namespaces are limited to ', max_namespace_len, ' characters'
84 call mpi_world%abort()
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
121
122 end function namespace_get
124 ! ---------------------------------------------------------
125 pure recursive function namespace_len(this)
126 class(namespace_t), intent(in) :: this
127 integer :: namespace_len
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
226 ! ----------------------------------------------------------
234 !
235 function namespace_get_hash32(this) result(h)
236 class(namespace_t), intent(in) :: this
237 !!
238
239 character(len=MAX_NAMESPACE_LEN) :: ns
240 integer(int64) :: h
241 integer :: i
242 integer(int64), parameter :: offset_basis = int(z'811C9DC5', int64)
243 integer(int64), parameter :: fnv_prime = int(z'01000193', int64)
244 integer(int64), parameter :: mask32 = int(z'FFFFFFFF', int64)
245
246 ns = this%get()
247
248 h = offset_basis
249 do i = 1, len_trim(ns)
250 h = ieor(h, int(iachar(ns(i:i)), int64))
251 h = h * fnv_prime ! wraps modulo 2^32 by integer overflow on 2s complement
252 h = iand(h, mask32) ! Force mod 2^32 behavior (important on some compilers/opts)
253 end do
254
255 end function namespace_get_hash32
256
257
258end module namespace_oct_m
259
260!! Local Variables:
261!! mode: f90
262!! coding: utf-8
263!! End:
type(mpi_grp_t), public mpi_world
Definition: mpi.F90:272
integer(int64) function namespace_get_hash32(this)
FNV-1a 32-bit hash of a namespace string (ASCII/byte-wise).
Definition: namespace.F90:331
logical function namespace_is_contained_in(this, name, delimiter)
Definition: namespace.F90:281
elemental logical function namespace_equal(lhs, rhs)
Definition: namespace.F90:238
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:145
logical function namespace_contains(this, namespace)
Definition: namespace.F90:247
type(namespace_t), public global_namespace
Definition: namespace.F90:135
pure recursive integer function namespace_len(this)
Definition: namespace.F90:221
recursive character(len=max_namespace_len) function namespace_get(this, delimiter)
get full name, including parents
Definition: namespace.F90:198
int true(void)