Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
libcifpp
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
libcifpp
Commits
2792caec
Unverified
Commit
2792caec
authored
Jan 23, 2024
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
renaming field and column to item
parent
fb2b1e98
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
499 additions
and
234 deletions
+499
-234
include/cif++/category.hpp
+0
-0
include/cif++/condition.hpp
+42
-33
include/cif++/item.hpp
+9
-9
include/cif++/iterator.hpp
+26
-26
include/cif++/model.hpp
+7
-7
include/cif++/parser.hpp
+2
-2
include/cif++/pdb.hpp
+41
-0
include/cif++/row.hpp
+41
-41
include/cif++/validate.hpp
+134
-15
src/category.cpp
+0
-0
src/condition.cpp
+9
-9
src/item.cpp
+5
-5
src/parser.cpp
+5
-5
src/pdb/pdb2cif_remark_3.cpp
+2
-2
src/pdb/reconstruct.cpp
+43
-18
src/pdb/validate-pdbx.cpp
+60
-18
src/row.cpp
+11
-11
src/validate.cpp
+62
-33
No files found.
include/cif++/category.hpp
View file @
2792caec
This diff is collapsed.
Click to expand it.
include/cif++/condition.hpp
View file @
2792caec
...
...
@@ -39,17 +39,17 @@
* query you can use to find rows in a @ref cif::category
*
* Conditions are created as standard C++ expressions. That means
* you can use the standard comparison operators to compare
field
* you can use the standard comparison operators to compare
item
* contents with a value and boolean operators to chain everything
* together.
*
* To create a query that simply compares one
field
with one value:
* To create a query that simply compares one
item
with one value:
*
* @code {.cpp}
* cif::condition c = cif::key("id") == 1;
* @endcode
*
* That will find rows where the ID
field
contains the number 1. If
* That will find rows where the ID
item
contains the number 1. If
* using cif::key is a bit too much typing, you can also write:
*
* @code{.cpp}
...
...
@@ -64,7 +64,7 @@
* auto c3 = "id"_key == 1 or "id"_key == 2;
* @endcode
*
* There are some special values you can use. To find rows with
field
that
* There are some special values you can use. To find rows with
item
that
* do not have a value:
*
* @code{.cpp}
...
...
@@ -83,7 +83,7 @@
* auto c6 = cif::all;
* @endcode
*
* And when you want to search for any
column
containing the value 'foo':
* And when you want to search for any
item
containing the value 'foo':
*
* @code{.cpp}
* auto c7 = cif::any == "foo";
...
...
@@ -104,31 +104,40 @@ namespace cif
/// we declare a function to access its contents
/**
* @brief Get the
field
s that can be used as key in conditions for a category
* @brief Get the
item
s that can be used as key in conditions for a category
*
* @param cat The category whose
field
s to return
* @return iset The set of key
field
names
* @param cat The category whose
item
s to return
* @return iset The set of key
item
names
*/
[[
deprecated
(
"use get_category_items instead"
)]]
iset
get_category_fields
(
const
category
&
cat
);
/**
* @brief Get the column index for column @a col in category @a cat
* @brief Get the items that can be used as key in conditions for a category
*
* @param cat The category whose items to return
* @return iset The set of key field names
*/
iset
get_category_items
(
const
category
&
cat
);
/**
* @brief Get the item index for item @a col in category @a cat
*
* @param cat The category
* @param col The name of the
column
* @param col The name of the
item
* @return uint16_t The index
*/
uint16_t
get_
column
_ix
(
const
category
&
cat
,
std
::
string_view
col
);
uint16_t
get_
item
_ix
(
const
category
&
cat
,
std
::
string_view
col
);
/**
* @brief Return whether the
column
@a col in category @a cat has a primitive type of *uchar*
* @brief Return whether the
item
@a col in category @a cat has a primitive type of *uchar*
*
* @param cat The category
* @param col The
column
name
* @param col The
item
name
* @return true If the primitive type is of type *uchar*
* @return false If the primitive type is not of type *uchar*
*/
bool
is_
column
_type_uchar
(
const
category
&
cat
,
std
::
string_view
col
);
bool
is_
item
_type_uchar
(
const
category
&
cat
,
std
::
string_view
col
);
// --------------------------------------------------------------------
// some more templates to be able to do querying
...
...
@@ -219,7 +228,7 @@ class condition
/**
* @brief Prepare the condition to be used on category @a c. This will
* take care of setting the correct indices for
field
s e.g.
* take care of setting the correct indices for
item
s e.g.
*
* @param c The category this query should act upon
*/
...
...
@@ -312,7 +321,7 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
return
this
;
}
...
...
@@ -339,7 +348,7 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
return
this
;
}
...
...
@@ -415,8 +424,8 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_icase
=
is_
column
_type_uchar
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
m_icase
=
is_
item
_type_uchar
(
c
,
m_item_tag
);
return
this
;
}
...
...
@@ -473,8 +482,8 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_icase
=
is_
column
_type_uchar
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
m_icase
=
is_
item
_type_uchar
(
c
,
m_item_tag
);
return
this
;
}
...
...
@@ -506,7 +515,7 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
return
this
;
}
...
...
@@ -541,7 +550,7 @@ namespace detail
auto
&
c
=
r
.
get_category
();
bool
result
=
false
;
for
(
auto
&
f
:
get_category_
field
s
(
c
))
for
(
auto
&
f
:
get_category_
item
s
(
c
))
{
try
{
...
...
@@ -579,7 +588,7 @@ namespace detail
auto
&
c
=
r
.
get_category
();
bool
result
=
false
;
for
(
auto
&
f
:
get_category_
field
s
(
c
))
for
(
auto
&
f
:
get_category_
item
s
(
c
))
{
try
{
...
...
@@ -887,7 +896,7 @@ inline condition operator or(condition &&a, condition &&b)
}
/**
* @brief A helper class to make it possible to search for empty
field
s (NULL)
* @brief A helper class to make it possible to search for empty
item
s (NULL)
*
* @code{.cpp}
* "id"_key == cif::empty_type();
...
...
@@ -909,7 +918,7 @@ struct empty_type
inline
constexpr
empty_type
null
=
empty_type
();
/**
* @brief Class to use in creating conditions, creates a reference to a
field or column
* @brief Class to use in creating conditions, creates a reference to a
item or item
*
*/
struct
key
...
...
@@ -947,7 +956,7 @@ struct key
key
(
const
key
&
)
=
delete
;
key
&
operator
=
(
const
key
&
)
=
delete
;
std
::
string
m_item_tag
;
///< The
column
name
std
::
string
m_item_tag
;
///< The
item
name
};
/**
...
...
@@ -1072,7 +1081,7 @@ inline condition operator!=(const key &key, const empty_type &)
}
/**
* @brief Create a condition to search any
column
for a value @a v if @a v contains a value
* @brief Create a condition to search any
item
for a value @a v if @a v contains a value
* compare to null if not.
*/
template
<
typename
T
>
...
...
@@ -1099,12 +1108,12 @@ struct any_type
/** @endcond */
/**
* @brief A helper for any
field
constructs
* @brief A helper for any
item
constructs
*/
inline
constexpr
any_type
any
=
any_type
{};
/**
* @brief Create a condition to search any
column
for a value @a v
* @brief Create a condition to search any
item
for a value @a v
*/
template
<
typename
T
>
condition
operator
==
(
const
any_type
&
,
const
T
&
v
)
...
...
@@ -1113,7 +1122,7 @@ condition operator==(const any_type &, const T &v)
}
/**
* @brief Create a condition to search any
column
for a regular expression @a rx
* @brief Create a condition to search any
item
for a regular expression @a rx
*/
inline
condition
operator
==
(
const
any_type
&
,
const
std
::
regex
&
rx
)
{
...
...
@@ -1131,9 +1140,9 @@ inline condition all()
namespace
literals
{
/**
* @brief Return a cif::key for the
column
name @a text
* @brief Return a cif::key for the
item
name @a text
*
* @param text The name of the
column
* @param text The name of the
item
* @param length The length of @a text
* @return key The cif::key created
*/
...
...
include/cif++/item.hpp
View file @
2792caec
...
...
@@ -44,7 +44,7 @@
/** \file item.hpp
*
* This file contains the declaration of item but also the item_value and item_handle
* These handle the storage of and access to the data for a single data
field
.
* These handle the storage of and access to the data for a single data
item
.
*/
namespace
cif
...
...
@@ -227,10 +227,10 @@ class item
/// \brief empty means either null or unknown
bool
empty
()
const
{
return
m_value
.
empty
();
}
/// \brief returns true if the
field
contains '.'
/// \brief returns true if the
item
contains '.'
bool
is_null
()
const
{
return
m_value
==
"."
;
}
/// \brief returns true if the
field
contains '?'
/// \brief returns true if the
item
contains '?'
bool
is_unknown
()
const
{
return
m_value
==
"?"
;
}
/// \brief the length of the value string
...
...
@@ -464,14 +464,14 @@ struct item_handle
/** Easy way to test for an empty item */
explicit
operator
bool
()
const
{
return
not
empty
();
}
/// is_null return true if the
field
contains '.'
/// is_null return true if the
item
contains '.'
bool
is_null
()
const
{
auto
txt
=
text
();
return
txt
.
length
()
==
1
and
txt
.
front
()
==
'.'
;
}
/// is_unknown returns true if the
field
contains '?'
/// is_unknown returns true if the
item
contains '?'
bool
is_unknown
()
const
{
auto
txt
=
text
();
...
...
@@ -484,11 +484,11 @@ struct item_handle
/**
* @brief Construct a new item handle object
*
* @param
column Column
index
* @param
item Item
index
* @param row Reference to the row
*/
item_handle
(
uint16_t
column
,
row_handle
&
row
)
:
m_
column
(
column
)
item_handle
(
uint16_t
item
,
row_handle
&
row
)
:
m_
item_ix
(
item
)
,
m_row_handle
(
row
)
{
}
...
...
@@ -505,7 +505,7 @@ struct item_handle
private
:
item_handle
();
uint16_t
m_
column
;
uint16_t
m_
item_ix
;
row_handle
&
m_row_handle
;
void
assign_value
(
const
item
&
value
);
...
...
include/cif++/iterator.hpp
View file @
2792caec
...
...
@@ -90,7 +90,7 @@ class iterator_impl
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_value
(
rhs
.
m_value
)
,
m_
column_ix
(
rhs
.
m_column
_ix
)
,
m_
item_ix
(
rhs
.
m_item
_ix
)
{
}
...
...
@@ -99,7 +99,7 @@ class iterator_impl
:
m_category
(
rhs
.
m_category
)
,
m_current
(
const_cast
<
row_type
*>
(
rhs
.
m_current
))
,
m_value
(
rhs
.
m_value
)
,
m_
column_ix
(
rhs
.
m_column
_ix
)
,
m_
item_ix
(
rhs
.
m_item
_ix
)
{
m_value
=
get
(
std
::
make_index_sequence
<
N
>
());
}
...
...
@@ -108,7 +108,7 @@ class iterator_impl
iterator_impl
(
const
iterator_impl
<
IRowType
>
&
rhs
,
const
std
::
array
<
uint16_t
,
N
>
&
cix
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_
column
_ix
(
cix
)
,
m_
item
_ix
(
cix
)
{
m_value
=
get
(
std
::
make_index_sequence
<
N
>
());
}
...
...
@@ -117,7 +117,7 @@ class iterator_impl
{
m_category
=
i
.
m_category
;
m_current
=
i
.
m_current
;
m_
column_ix
=
i
.
m_column
_ix
;
m_
item_ix
=
i
.
m_item
_ix
;
m_value
=
i
.
m_value
;
return
*
this
;
}
...
...
@@ -185,7 +185,7 @@ class iterator_impl
if
(
m_current
!=
nullptr
)
{
row_handle
rh
{
*
m_category
,
*
m_current
};
return
tuple_type
{
rh
[
m_
column
_ix
[
Is
]].
template
as
<
Ts
>
()...
};
return
tuple_type
{
rh
[
m_
item
_ix
[
Is
]].
template
as
<
Ts
>
()...
};
}
return
{};
...
...
@@ -194,7 +194,7 @@ class iterator_impl
category_type
*
m_category
=
nullptr
;
row_type
*
m_current
=
nullptr
;
value_type
m_value
;
std
::
array
<
uint16_t
,
N
>
m_
column
_ix
;
std
::
array
<
uint16_t
,
N
>
m_
item
_ix
;
};
/**
...
...
@@ -348,7 +348,7 @@ class iterator_impl<Category, T>
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_value
(
rhs
.
m_value
)
,
m_
column_ix
(
rhs
.
m_column
_ix
)
,
m_
item_ix
(
rhs
.
m_item
_ix
)
{
}
...
...
@@ -357,7 +357,7 @@ class iterator_impl<Category, T>
:
m_category
(
rhs
.
m_category
)
,
m_current
(
const_cast
<
row_type
*>
(
rhs
.
m_current
))
,
m_value
(
rhs
.
m_value
)
,
m_
column_ix
(
rhs
.
m_column
_ix
)
,
m_
item_ix
(
rhs
.
m_item
_ix
)
{
m_value
=
get
(
m_current
);
}
...
...
@@ -366,7 +366,7 @@ class iterator_impl<Category, T>
iterator_impl
(
const
iterator_impl
<
IRowType
>
&
rhs
,
const
std
::
array
<
uint16_t
,
1
>
&
cix
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_
column
_ix
(
cix
[
0
])
,
m_
item
_ix
(
cix
[
0
])
{
m_value
=
get
();
}
...
...
@@ -375,7 +375,7 @@ class iterator_impl<Category, T>
{
m_category
=
i
.
m_category
;
m_current
=
i
.
m_current
;
m_
column_ix
=
i
.
m_column
_ix
;
m_
item_ix
=
i
.
m_item
_ix
;
m_value
=
i
.
m_value
;
return
*
this
;
}
...
...
@@ -442,7 +442,7 @@ class iterator_impl<Category, T>
if
(
m_current
!=
nullptr
)
{
row_handle
rh
{
*
m_category
,
*
m_current
};
return
rh
[
m_
column
_ix
].
template
as
<
T
>
();
return
rh
[
m_
item
_ix
].
template
as
<
T
>
();
}
return
{};
...
...
@@ -451,7 +451,7 @@ class iterator_impl<Category, T>
category_type
*
m_category
=
nullptr
;
row_type
*
m_current
=
nullptr
;
value_type
m_value
;
uint16_t
m_
column
_ix
;
uint16_t
m_
item
_ix
;
};
// --------------------------------------------------------------------
...
...
@@ -482,8 +482,8 @@ class iterator_proxy
using
iterator
=
iterator_impl
<
category_type
,
Ts
...
>
;
using
row_iterator
=
iterator_impl
<
category_type
>
;
iterator_proxy
(
category_type
&
cat
,
row_iterator
pos
,
char
const
*
const
column
s
[
N
]);
iterator_proxy
(
category_type
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
column
s
);
iterator_proxy
(
category_type
&
cat
,
row_iterator
pos
,
char
const
*
const
item
s
[
N
]);
iterator_proxy
(
category_type
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
item
s
);
iterator_proxy
(
iterator_proxy
&&
p
);
iterator_proxy
&
operator
=
(
iterator_proxy
&&
p
);
...
...
@@ -492,8 +492,8 @@ class iterator_proxy
iterator_proxy
&
operator
=
(
const
iterator_proxy
&
)
=
delete
;
/** @endcond */
iterator
begin
()
const
{
return
iterator
(
m_begin
,
m_
column
_ix
);
}
///< Return the iterator pointing to the first row
iterator
end
()
const
{
return
iterator
(
m_end
,
m_
column
_ix
);
}
///< Return the iterator pointing past the last row
iterator
begin
()
const
{
return
iterator
(
m_begin
,
m_
item
_ix
);
}
///< Return the iterator pointing to the first row
iterator
end
()
const
{
return
iterator
(
m_end
,
m_
item
_ix
);
}
///< Return the iterator pointing past the last row
bool
empty
()
const
{
return
m_begin
==
m_end
;
}
///< Return true if the range is empty
explicit
operator
bool
()
const
{
return
not
empty
();
}
///< Easy way to detect if the range is empty
...
...
@@ -510,13 +510,13 @@ class iterator_proxy
std
::
swap
(
m_category
,
rhs
.
m_category
);
std
::
swap
(
m_begin
,
rhs
.
m_begin
);
std
::
swap
(
m_end
,
rhs
.
m_end
);
std
::
swap
(
m_
column_ix
,
rhs
.
m_column
_ix
);
std
::
swap
(
m_
item_ix
,
rhs
.
m_item
_ix
);
}
private
:
category_type
*
m_category
;
row_iterator
m_begin
,
m_end
;
std
::
array
<
uint16_t
,
N
>
m_
column
_ix
;
std
::
array
<
uint16_t
,
N
>
m_
item
_ix
;
};
// --------------------------------------------------------------------
...
...
@@ -651,26 +651,26 @@ class conditional_iterator_proxy
/** @cond */
template
<
typename
Category
,
typename
...
Ts
>
iterator_proxy
<
Category
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
char
const
*
const
column
s
[
N
])
iterator_proxy
<
Category
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
char
const
*
const
item
s
[
N
])
:
m_category
(
&
cat
)
,
m_begin
(
pos
)
,
m_end
(
cat
.
end
())
{
for
(
uint16_t
i
=
0
;
i
<
N
;
++
i
)
m_
column_ix
[
i
]
=
m_category
->
get_column_ix
(
column
s
[
i
]);
m_
item_ix
[
i
]
=
m_category
->
get_item_ix
(
item
s
[
i
]);
}
template
<
typename
Category
,
typename
...
Ts
>
iterator_proxy
<
Category
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
column
s
)
iterator_proxy
<
Category
,
Ts
...
>::
iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
std
::
initializer_list
<
char
const
*>
item
s
)
:
m_category
(
&
cat
)
,
m_begin
(
pos
)
,
m_end
(
cat
.
end
())
{
// static_assert(
columns.size() == N, "The list of column names should be exactly the same as the list of requested column
s");
// static_assert(
items.size() == N, "The list of item names should be exactly the same as the list of requested item
s");
std
::
uint16_t
i
=
0
;
for
(
auto
column
:
column
s
)
m_
column_ix
[
i
++
]
=
m_category
->
get_column_ix
(
column
);
for
(
auto
item
:
item
s
)
m_
item_ix
[
i
++
]
=
m_category
->
get_item_ix
(
item
);
}
// --------------------------------------------------------------------
...
...
@@ -707,7 +707,7 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
,
mCBegin
(
pos
)
,
mCEnd
(
cat
.
end
())
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"Number of
column
names should be equal to number of requested value types"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"Number of
item
names should be equal to number of requested value types"
);
if
(
m_condition
)
{
...
...
@@ -720,7 +720,7 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
mCBegin
=
mCEnd
;
uint16_t
i
=
0
;
((
mCix
[
i
++
]
=
m_cat
->
get_
column
_ix
(
names
)),
...);
((
mCix
[
i
++
]
=
m_cat
->
get_
item
_ix
(
names
)),
...);
}
template
<
typename
Category
,
typename
...
Ts
>
...
...
include/cif++/model.hpp
View file @
2792caec
...
...
@@ -72,7 +72,7 @@ class structure;
*
* The class atom is a kind of flyweight class. It can be copied
* with low overhead. All data is stored in the underlying mmCIF
* categories but some very often used
field
s are cached in the
* categories but some very often used
item
s are cached in the
* impl.
*
* It is also possible to have symmetry copies of atoms. They
...
...
@@ -207,7 +207,7 @@ class atom
/// \brief Copy assignement operator
atom
&
operator
=
(
const
atom
&
rhs
)
=
default
;
/// \brief Return the
field
named @a name in the _atom_site category for this atom
/// \brief Return the
item
named @a name in the _atom_site category for this atom
std
::
string
get_property
(
std
::
string_view
name
)
const
{
if
(
not
m_impl
)
...
...
@@ -215,7 +215,7 @@ class atom
return
m_impl
->
get_property
(
name
);
}
/// \brief Return the
field
named @a name in the _atom_site category for this atom cast to an int
/// \brief Return the
item
named @a name in the _atom_site category for this atom cast to an int
int
get_property_int
(
std
::
string_view
name
)
const
{
if
(
not
m_impl
)
...
...
@@ -223,7 +223,7 @@ class atom
return
m_impl
->
get_property_int
(
name
);
}
/// \brief Return the
field
named @a name in the _atom_site category for this atom cast to a float
/// \brief Return the
item
named @a name in the _atom_site category for this atom cast to a float
float
get_property_float
(
std
::
string_view
name
)
const
{
if
(
not
m_impl
)
...
...
@@ -231,7 +231,7 @@ class atom
return
m_impl
->
get_property_float
(
name
);
}
/// \brief Set value for the
field
named @a name in the _atom_site category to @a value
/// \brief Set value for the
item
named @a name in the _atom_site category to @a value
void
set_property
(
const
std
::
string_view
name
,
const
std
::
string
&
value
)
{
if
(
not
m_impl
)
...
...
@@ -239,7 +239,7 @@ class atom
m_impl
->
set_property
(
name
,
value
);
}
/// \brief Set value for the
field
named @a name in the _atom_site category to @a value
/// \brief Set value for the
item
named @a name in the _atom_site category to @a value
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
void
set_property
(
const
std
::
string_view
name
,
const
T
&
value
)
{
...
...
@@ -730,7 +730,7 @@ class sugar : public residue
/**
* @brief Return the sugar number in the glycosylation tree
*
* To store the sugar number, the auth_seq_id
field
has been overloaded
* To store the sugar number, the auth_seq_id
item
has been overloaded
* in the specification. But since a sugar number should be, ehm, a number
* and auth_seq_id is specified to contain a string, we do a check here
* to see if it really is a number.
...
...
include/cif++/parser.hpp
View file @
2792caec
...
...
@@ -268,8 +268,8 @@ class sac_parser
QuotedStringQuote
,
UnquotedString
,
Tag
,
Text
Field
,
Text
Field
NL
,
Text
Item
,
Text
Item
NL
,
Reserved
,
Value
};
...
...
include/cif++/pdb.hpp
View file @
2792caec
...
...
@@ -28,6 +28,8 @@
#include "cif++/file.hpp"
#include <system_error>
/**
* @file pdb.hpp
*
...
...
@@ -119,6 +121,8 @@ void reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx
* atom_site -> pdbx_poly_seq_scheme -> entity_poly_seq -> entity_poly -> entity
*
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
*
* This function throws a std::system_error in case of an error
*
* \param file The input file
* \param dictionary The mmcif dictionary to use
...
...
@@ -127,6 +131,43 @@ void reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx
bool
is_valid_pdbx_file
(
const
file
&
pdbx_file
,
std
::
string_view
dictionary
=
"mmcif_pdbx"
);
/** \brief This is an extension to cif::validator, use the logic in common
* PDBx files to see if the file is internally consistent.
*
* This function for now checks if the following categories are consistent:
*
* atom_site -> pdbx_poly_seq_scheme -> entity_poly_seq -> entity_poly -> entity
*
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
*
* The dictionary is assumed to be specified in the file or to be the
* default mmcif_pdbx.dic dictionary.
*
* \param file The input file
* \param ec The error_code in case something was wrong
* \result Returns true if the file was valid and consistent
*/
bool
is_valid_pdbx_file
(
const
file
&
pdbx_file
,
std
::
error_code
&
ec
);
/** \brief This is an extension to cif::validator, use the logic in common
* PDBx files to see if the file is internally consistent.
*
* This function for now checks if the following categories are consistent:
*
* atom_site -> pdbx_poly_seq_scheme -> entity_poly_seq -> entity_poly -> entity
*
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
*
* \param file The input file
* \param dictionary The dictionary to use
* \param ec The error_code in case something was wrong
* \result Returns true if the file was valid and consistent
*/
bool
is_valid_pdbx_file
(
const
file
&
pdbx_file
,
std
::
string_view
dictionary
,
std
::
error_code
&
ec
);
// --------------------------------------------------------------------
// Other I/O related routines
...
...
include/cif++/row.hpp
View file @
2792caec
...
...
@@ -51,7 +51,7 @@
* std::string name = rh["label_atom_id"].as<std::string>();
*
* // by index:
* uint16_t ix = atom_site.get_
column
_ix("label_atom_id");
* uint16_t ix = atom_site.get_
item
_ix("label_atom_id");
* assert(rh[ix].as<std::string() == name);
* @endcode
*
...
...
@@ -87,15 +87,15 @@ namespace detail
{
static
constexpr
size_t
N
=
sizeof
...(
C
);
get_row_result
(
const
row_handle
&
r
,
std
::
array
<
uint16_t
,
N
>
&&
column
s
)
get_row_result
(
const
row_handle
&
r
,
std
::
array
<
uint16_t
,
N
>
&&
item
s
)
:
m_row
(
r
)
,
m_
columns
(
std
::
move
(
column
s
))
,
m_
items
(
std
::
move
(
item
s
))
{
}
const
item_handle
operator
[](
uint16_t
ix
)
const
{
return
m_row
[
m_
column
s
[
ix
]];
return
m_row
[
m_
item
s
[
ix
]];
}
template
<
typename
...
Ts
,
std
::
enable_if_t
<
N
==
sizeof
...(
Ts
),
int
>
=
0
>
...
...
@@ -107,11 +107,11 @@ namespace detail
template
<
typename
...
Ts
,
size_t
...
Is
>
std
::
tuple
<
Ts
...
>
get
(
std
::
index_sequence
<
Is
...
>
)
const
{
return
std
::
tuple
<
Ts
...
>
{
m_row
[
m_
column
s
[
Is
]].
template
as
<
Ts
>
()...
};
return
std
::
tuple
<
Ts
...
>
{
m_row
[
m_
item
s
[
Is
]].
template
as
<
Ts
>
()...
};
}
const
row_handle
&
m_row
;
std
::
array
<
uint16_t
,
N
>
m_
column
s
;
std
::
array
<
uint16_t
,
N
>
m_
item
s
;
};
// we want to be able to tie some variables to a get_row_result, for this we use tiewraps
...
...
@@ -244,70 +244,70 @@ class row_handle
return
not
empty
();
}
/// \brief return a cif::item_handle to the item in
column @a column
_ix
item_handle
operator
[](
uint16_t
column
_ix
)
/// \brief return a cif::item_handle to the item in
item @a item
_ix
item_handle
operator
[](
uint16_t
item
_ix
)
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
column
_ix
,
*
this
);
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
item
_ix
,
*
this
);
}
/// \brief return a const cif::item_handle to the item in
column @a column
_ix
const
item_handle
operator
[](
uint16_t
column
_ix
)
const
/// \brief return a const cif::item_handle to the item in
item @a item
_ix
const
item_handle
operator
[](
uint16_t
item
_ix
)
const
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
column
_ix
,
const_cast
<
row_handle
&>
(
*
this
));
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
item
_ix
,
const_cast
<
row_handle
&>
(
*
this
));
}
/// \brief return a cif::item_handle to the item in the
column named @a column
_name
item_handle
operator
[](
std
::
string_view
column
_name
)
/// \brief return a cif::item_handle to the item in the
item named @a item
_name
item_handle
operator
[](
std
::
string_view
item
_name
)
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
add_
column
(
column
_name
),
*
this
);
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
add_
item
(
item
_name
),
*
this
);
}
/// \brief return a const cif::item_handle to the item in the
column named @a column
_name
const
item_handle
operator
[](
std
::
string_view
column
_name
)
const
/// \brief return a const cif::item_handle to the item in the
item named @a item
_name
const
item_handle
operator
[](
std
::
string_view
item
_name
)
const
{
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
get_
column_ix
(
column
_name
),
const_cast
<
row_handle
&>
(
*
this
));
return
empty
()
?
item_handle
::
s_null_item
:
item_handle
(
get_
item_ix
(
item
_name
),
const_cast
<
row_handle
&>
(
*
this
));
}
/// \brief Return an object that can be used in combination with cif::tie
/// to assign the values for the
columns @a column
s
/// to assign the values for the
items @a item
s
template
<
typename
...
C
>
auto
get
(
C
...
column
s
)
const
auto
get
(
C
...
item
s
)
const
{
return
detail
::
get_row_result
<
C
...
>
(
*
this
,
{
get_
column_ix
(
column
s
)...
});
return
detail
::
get_row_result
<
C
...
>
(
*
this
,
{
get_
item_ix
(
item
s
)...
});
}
/// \brief Return a tuple of values of types @a Ts for the
columns @a column
s
/// \brief Return a tuple of values of types @a Ts for the
items @a item
s
template
<
typename
...
Ts
,
typename
...
C
,
std
::
enable_if_t
<
sizeof
...(
Ts
)
==
sizeof
...(
C
)
and
sizeof
...(
C
)
!=
1
,
int
>
=
0
>
std
::
tuple
<
Ts
...
>
get
(
C
...
column
s
)
const
std
::
tuple
<
Ts
...
>
get
(
C
...
item
s
)
const
{
return
detail
::
get_row_result
<
Ts
...
>
(
*
this
,
{
get_
column_ix
(
column
s
)...
});
return
detail
::
get_row_result
<
Ts
...
>
(
*
this
,
{
get_
item_ix
(
item
s
)...
});
}
/// \brief Get the value of
column @a column
cast to type @a T
/// \brief Get the value of
item @a item
cast to type @a T
template
<
typename
T
>
T
get
(
const
char
*
column
)
const
T
get
(
const
char
*
item
)
const
{
return
operator
[](
get_
column_ix
(
column
)).
template
as
<
T
>
();
return
operator
[](
get_
item_ix
(
item
)).
template
as
<
T
>
();
}
/// \brief Get the value of
column @a column
cast to type @a T
/// \brief Get the value of
item @a item
cast to type @a T
template
<
typename
T
>
T
get
(
std
::
string_view
column
)
const
T
get
(
std
::
string_view
item
)
const
{
return
operator
[](
get_
column_ix
(
column
)).
template
as
<
T
>
();
return
operator
[](
get_
item_ix
(
item
)).
template
as
<
T
>
();
}
/// \brief assign each of the
column
s named in @a values to their respective value
/// \brief assign each of the
item
s named in @a values to their respective value
void
assign
(
const
std
::
vector
<
item
>
&
values
)
{
for
(
auto
&
value
:
values
)
assign
(
value
,
true
);
}
/** \brief assign the value @a value to the
column
named @a name
/** \brief assign the value @a value to the
item
named @a name
*
* If updateLinked it true, linked records are updated as well.
* That means that if
column
@a name is part of the link definition
* That means that if
item
@a name is part of the link definition
* and the link results in a linked record in another category
* this record in the linked category is updated as well.
*
...
...
@@ -317,13 +317,13 @@ class row_handle
void
assign
(
std
::
string_view
name
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
)
{
assign
(
add_
column
(
name
),
value
,
updateLinked
,
validate
);
assign
(
add_
item
(
name
),
value
,
updateLinked
,
validate
);
}
/** \brief assign the value @a value to
column at index @a column
/** \brief assign the value @a value to
item at index @a item
*
* If updateLinked it true, linked records are updated as well.
* That means that if
column @a column
is part of the link definition
* That means that if
item @a item
is part of the link definition
* and the link results in a linked record in another category
* this record in the linked category is updated as well.
*
...
...
@@ -331,7 +331,7 @@ class row_handle
* checked to see if it conforms to the rules defined in the dictionary
*/
void
assign
(
uint16_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
void
assign
(
uint16_t
item
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
/// \brief compare two rows
bool
operator
==
(
const
row_handle
&
rhs
)
const
{
return
m_category
==
rhs
.
m_category
and
m_row
==
rhs
.
m_row
;
}
...
...
@@ -340,10 +340,10 @@ class row_handle
bool
operator
!=
(
const
row_handle
&
rhs
)
const
{
return
m_category
!=
rhs
.
m_category
or
m_row
!=
rhs
.
m_row
;
}
private
:
uint16_t
get_
column
_ix
(
std
::
string_view
name
)
const
;
std
::
string_view
get_
column
_name
(
uint16_t
ix
)
const
;
uint16_t
get_
item
_ix
(
std
::
string_view
name
)
const
;
std
::
string_view
get_
item
_name
(
uint16_t
ix
)
const
;
uint16_t
add_
column
(
std
::
string_view
name
);
uint16_t
add_
item
(
std
::
string_view
name
);
row
*
get_row
()
{
...
...
@@ -360,7 +360,7 @@ class row_handle
assign
(
i
.
name
(),
i
.
value
(),
updateLinked
);
}
void
swap
(
uint16_t
column
,
row_handle
&
r
);
void
swap
(
uint16_t
item
,
row_handle
&
r
);
category
*
m_category
=
nullptr
;
row
*
m_row
=
nullptr
;
...
...
include/cif++/validate.hpp
View file @
2792caec
...
...
@@ -28,9 +28,11 @@
#include "cif++/text.hpp"
#include <cassert>
#include <filesystem>
#include <list>
#include <mutex>
#include <system_error>
#include <utility>
/**
...
...
@@ -49,29 +51,123 @@ namespace cif
struct
category_validator
;
// --------------------------------------------------------------------
// New: error_code
/**
* @
brief The exception thrown when a validation error occurs
* @
enum validation_error
*
* @brief A stronly typed class containing the error codes reported by @ref cif::validator and friends
*/
class
validation_error
:
public
std
::
exception
enum
class
validation_error
{
value_does_not_match_rx
=
1
,
/**< The value of an item does not conform to the regular expression specified for it */
value_is_not_in_enumeration_list
,
/**< The value of an item is not in the list of values allowed */
not_a_known_primitive_type
,
/**< The type is not a known primitive type */
undefined_category
,
/**< Category has no definition in the dictionary */
unknown_item
,
/**< The item is not defined to be part of the category */
incorrect_item_validator
,
/**< Incorrectly specified validator for item */
missing_mandatory_items
,
/**< Missing mandatory items */
missing_key_items
,
/**< An index could not be constructed due to missing key items */
item_not_allowed_in_category
,
/**< Requested item allowed in category according to dictionary */
empty_file
,
/**< The file contains no datablocks */
empty_datablock
,
/**< The datablock contains no categories */
empty_category
,
/**< The category is empty */
not_valid_pdbx
,
/**< The file is not a valid PDBx file */
};
/**
* @brief The implementation for @ref validation_category error messages
*
*/
class
validation_category_impl
:
public
std
::
error_category
{
public
:
/// @brief Constructor
validation_error
(
const
std
::
string
&
msg
);
/**
* @brief User friendly name
*
* @return const char*
*/
/// @brief Constructor
validation_error
(
const
std
::
string
&
cat
,
const
std
::
string
&
item
,
const
std
::
string
&
msg
);
const
char
*
name
()
const
noexcept
override
{
return
"cif::validation"
;
}
/// @brief The description of the error
const
char
*
what
()
const
noexcept
{
return
m_msg
.
c_str
();
}
/**
* @brief Provide the error message as a string for the error code @a ev
*
* @param ev The error code
* @return std::string
*/
std
::
string
message
(
int
ev
)
const
override
{
switch
(
static_cast
<
validation_error
>
(
ev
))
{
case
validation_error
:
:
value_does_not_match_rx
:
return
"Value in item does not match regular expression"
;
case
validation_error
:
:
value_is_not_in_enumeration_list
:
return
"Value is not in the enumerated list of valid values"
;
case
validation_error
:
:
not_a_known_primitive_type
:
return
"The type is not a known primitive type"
;
case
validation_error
:
:
undefined_category
:
return
"Category has no definition in the dictionary"
;
case
validation_error
:
:
unknown_item
:
return
"The item is not defined to be part of the category"
;
case
validation_error
:
:
incorrect_item_validator
:
return
"Incorrectly specified validator for item"
;
case
validation_error
:
:
missing_mandatory_items
:
return
"Missing mandatory items"
;
case
validation_error
:
:
missing_key_items
:
return
"An index could not be constructed due to missing key items"
;
case
validation_error
:
:
item_not_allowed_in_category
:
return
"Requested item allowed in category according to dictionary"
;
case
validation_error
:
:
empty_file
:
return
"The file contains no datablocks"
;
case
validation_error
:
:
empty_datablock
:
return
"The datablock contains no categories"
;
case
validation_error
:
:
empty_category
:
return
"The category is empty"
;
case
validation_error
:
:
not_valid_pdbx
:
return
"The file is not a valid PDBx file"
;
default
:
assert
(
false
);
return
"unknown error code"
;
}
}
/// @cond
std
::
string
m_msg
;
/// @endcond
/**
* @brief Return whether two error codes are equivalent, always false in this case
*
*/
bool
equivalent
(
const
std
::
error_code
&
/*code*/
,
int
/*condition*/
)
const
noexcept
override
{
return
false
;
}
};
/**
* @brief Return the implementation for the validation_category
*
* @return std::error_category&
*/
inline
std
::
error_category
&
validation_category
()
{
static
validation_category_impl
instance
;
return
instance
;
}
inline
std
::
error_code
make_error_code
(
validation_error
e
)
{
return
std
::
error_code
(
static_cast
<
int
>
(
e
),
validation_category
());
}
inline
std
::
error_condition
make_error_condition
(
validation_error
e
)
{
return
std
::
error_condition
(
static_cast
<
int
>
(
e
),
validation_category
());
}
// --------------------------------------------------------------------
/** @brief the primitive types known */
...
...
@@ -85,6 +181,9 @@ enum class DDL_PrimitiveType
/// @brief Return the DDL_PrimitiveType encoded in @a s
DDL_PrimitiveType
map_to_primitive_type
(
std
::
string_view
s
);
/// @brief Return the DDL_PrimitiveType encoded in @a s, error reporting variant
DDL_PrimitiveType
map_to_primitive_type
(
std
::
string_view
s
,
std
::
error_code
&
ec
)
noexcept
;
struct
regex_impl
;
/**
...
...
@@ -188,8 +287,11 @@ struct item_validator
}
/// @brief Validate the value in @a value for this item
/// Will throw a
validation
_error exception if it fails
/// Will throw a
std::system
_error exception if it fails
void
operator
()(
std
::
string_view
value
)
const
;
/// @brief A more gentle version of value validation
bool
validate_value
(
std
::
string_view
value
,
std
::
error_code
&
ec
)
const
noexcept
;
};
/**
...
...
@@ -203,7 +305,7 @@ struct category_validator
std
::
string
m_name
;
///< The name of the category
std
::
vector
<
std
::
string
>
m_keys
;
///< The list of items that make up the key
cif
::
iset
m_groups
;
///< The category groups this category belongs to
cif
::
iset
m_mandatory_
fields
;
///< The mandatory field
s for this category
cif
::
iset
m_mandatory_
items
;
///< The mandatory item
s for this category
std
::
set
<
item_validator
>
m_item_validators
;
///< The item validators for the items in this category
/// @brief return true if this category sorts before @a rhs
...
...
@@ -298,7 +400,24 @@ class validator
std
::
vector
<
const
link_validator
*>
get_links_for_child
(
std
::
string_view
category
)
const
;
/// @brief Bottleneck function to report an error in validation
void
report_error
(
const
std
::
string
&
msg
,
bool
fatal
)
const
;
void
report_error
(
validation_error
err
,
bool
fatal
=
true
)
const
{
report_error
(
make_error_code
(
err
),
fatal
);
}
/// @brief Bottleneck function to report an error in validation
void
report_error
(
std
::
error_code
ec
,
bool
fatal
=
true
)
const
;
/// @brief Bottleneck function to report an error in validation
void
report_error
(
validation_error
err
,
std
::
string_view
category
,
std
::
string_view
item
,
bool
fatal
=
true
)
const
{
report_error
(
make_error_code
(
err
),
category
,
item
,
fatal
);
}
/// @brief Bottleneck function to report an error in validation
void
report_error
(
std
::
error_code
ec
,
std
::
string_view
category
,
std
::
string_view
item
,
bool
fatal
=
true
)
const
;
const
std
::
string
&
name
()
const
{
return
m_name
;
}
///< Get the name of this validator
void
set_name
(
const
std
::
string
&
name
)
{
m_name
=
name
;
}
///< Set the name of this validator
...
...
src/category.cpp
View file @
2792caec
This diff is collapsed.
Click to expand it.
src/condition.cpp
View file @
2792caec
...
...
@@ -30,17 +30,17 @@
namespace
cif
{
iset
get_category_
field
s
(
const
category
&
cat
)
iset
get_category_
item
s
(
const
category
&
cat
)
{
return
cat
.
key_
field
s
();
return
cat
.
key_
item
s
();
}
uint16_t
get_
column
_ix
(
const
category
&
cat
,
std
::
string_view
col
)
uint16_t
get_
item
_ix
(
const
category
&
cat
,
std
::
string_view
col
)
{
return
cat
.
get_
column
_ix
(
col
);
return
cat
.
get_
item
_ix
(
col
);
}
bool
is_
column
_type_uchar
(
const
category
&
cat
,
std
::
string_view
col
)
bool
is_
item
_type_uchar
(
const
category
&
cat
,
std
::
string_view
col
)
{
bool
result
=
false
;
...
...
@@ -63,12 +63,12 @@ namespace detail
condition_impl
*
key_equals_condition_impl
::
prepare
(
const
category
&
c
)
{
m_item_ix
=
c
.
get_
column
_ix
(
m_item_tag
);
m_icase
=
is_
column
_type_uchar
(
c
,
m_item_tag
);
m_item_ix
=
c
.
get_
item
_ix
(
m_item_tag
);
m_icase
=
is_
item
_type_uchar
(
c
,
m_item_tag
);
if
(
c
.
get_cat_validator
()
!=
nullptr
and
c
.
key_
field
_indices
().
contains
(
m_item_ix
)
and
c
.
key_
field
_indices
().
size
()
==
1
)
c
.
key_
item
_indices
().
contains
(
m_item_ix
)
and
c
.
key_
item
_indices
().
size
()
==
1
)
{
m_single_hit
=
c
[{
{
m_item_tag
,
m_value
}
}];
}
...
...
src/item.cpp
View file @
2792caec
...
...
@@ -35,7 +35,7 @@ const item_handle item_handle::s_null_item;
row_handle
s_null_row_handle
;
item_handle
::
item_handle
()
:
m_
column
(
std
::
numeric_limits
<
uint16_t
>::
max
())
:
m_
item_ix
(
std
::
numeric_limits
<
uint16_t
>::
max
())
,
m_row_handle
(
s_null_row_handle
)
{
}
...
...
@@ -44,7 +44,7 @@ std::string_view item_handle::text() const
{
if
(
not
m_row_handle
.
empty
())
{
auto
iv
=
m_row_handle
.
m_row
->
get
(
m_
column
);
auto
iv
=
m_row_handle
.
m_row
->
get
(
m_
item_ix
);
if
(
iv
!=
nullptr
)
return
iv
->
text
();
}
...
...
@@ -55,14 +55,14 @@ std::string_view item_handle::text() const
void
item_handle
::
assign_value
(
const
item
&
v
)
{
assert
(
not
m_row_handle
.
empty
());
m_row_handle
.
assign
(
m_
column
,
v
.
value
(),
true
);
m_row_handle
.
assign
(
m_
item_ix
,
v
.
value
(),
true
);
}
void
item_handle
::
swap
(
item_handle
&
b
)
{
assert
(
m_
column
==
b
.
m_column
);
assert
(
m_
item_ix
==
b
.
m_item_ix
);
// assert(&m_row_handle.m_category == &b.m_row_handle.m_category);
m_row_handle
.
swap
(
m_
column
,
b
.
m_row_handle
);
m_row_handle
.
swap
(
m_
item_ix
,
b
.
m_row_handle
);
}
}
src/parser.cpp
View file @
2792caec
...
...
@@ -300,7 +300,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
else
if
(
ch
==
'_'
)
state
=
State
::
Tag
;
else
if
(
ch
==
';'
and
m_bol
)
state
=
State
::
Text
Field
;
state
=
State
::
Text
Item
;
else
if
(
ch
==
'?'
)
state
=
State
::
QuestionMark
;
else
if
(
ch
==
'\''
or
ch
==
'"'
)
...
...
@@ -350,18 +350,18 @@ sac_parser::CIFToken sac_parser::get_next_token()
state
=
State
::
Value
;
break
;
case
State
:
:
Text
Field
:
case
State
:
:
Text
Item
:
if
(
ch
==
'\n'
)
state
=
State
::
Text
Field
NL
;
state
=
State
::
Text
Item
NL
;
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
else
if
(
not
is_any_print
(
ch
)
and
cif
::
VERBOSE
>
2
)
warning
(
"invalid character in text field '"
+
std
::
string
({
static_cast
<
char
>
(
ch
)})
+
"' ("
+
std
::
to_string
((
int
)
ch
)
+
")"
);
break
;
case
State
:
:
Text
Field
NL
:
case
State
:
:
Text
Item
NL
:
if
(
is_text_lead
(
ch
)
or
ch
==
' '
or
ch
==
'\t'
)
state
=
State
::
Text
Field
;
state
=
State
::
Text
Item
;
else
if
(
ch
==
';'
)
{
assert
(
m_token_buffer
.
size
()
>=
2
);
...
...
src/pdb/pdb2cif_remark_3.cpp
View file @
2792caec
...
...
@@ -1493,8 +1493,8 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
auto
r1
=
cat1
.
front
();
auto
r2
=
cat2
.
front
();
for
(
auto
column
:
cat1
.
key_field
s
())
r2
[
column
]
=
r1
[
column
].
text
();
for
(
auto
item
:
cat1
.
key_item
s
())
r2
[
item
]
=
r1
[
item
].
text
();
}
}
else
...
...
src/pdb/reconstruct.cpp
View file @
2792caec
...
...
@@ -237,7 +237,7 @@ void checkAtomRecords(datablock &db)
{
"auth_comp_id"
,
auth_comp_id
.
value_or
(
*
label_comp_id
)
},
{
"auth_atom_id"
,
auth_atom_id
.
value_or
(
*
label_atom_id
)
}
});
// Rewrite the coordinates and other
field
s that look better in a fixed format
// Rewrite the coordinates and other
item
s that look better in a fixed format
// Be careful not to nuke invalidly formatted data here
for
(
auto
[
tag
,
prec
]
:
std
::
vector
<
std
::
tuple
<
std
::
string_view
,
std
::
string
::
size_type
>>
{
{
"cartn_x"
,
3
},
...
...
@@ -267,8 +267,8 @@ void checkAtomRecords(datablock &db)
auto
*
cv
=
atom_site
.
get_cat_validator
();
if
(
cv
)
{
// See if there are
column
s that are no longer known
for
(
auto
tag
:
atom_site
.
get_
column
s
())
// See if there are
item
s that are no longer known
for
(
auto
tag
:
atom_site
.
get_
item
s
())
{
if
(
cv
->
get_validator_for_item
(
tag
)
!=
nullptr
)
continue
;
...
...
@@ -277,12 +277,12 @@ void checkAtomRecords(datablock &db)
if
(
not
r
)
{
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Dropping unknown
column
"
<<
tag
<<
'\n'
;
std
::
clog
<<
"Dropping unknown
item
"
<<
tag
<<
'\n'
;
atom_site
.
remove_
column
(
tag
);
atom_site
.
remove_
item
(
tag
);
}
else
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Keeping unknown
column
"
<<
std
::
quoted
(
tag
)
<<
" in atom_site since it is not empty
\n
"
;
std
::
clog
<<
"Keeping unknown
item
"
<<
std
::
quoted
(
tag
)
<<
" in atom_site since it is not empty
\n
"
;
}
}
}
...
...
@@ -311,10 +311,10 @@ void createEntity(datablock &db)
auto
&
cf
=
compound_factory
::
instance
();
auto
&
atom_site
=
db
[
"atom_site"
];
atom_site
.
add_
column
(
"label_entity_id"
);
atom_site
.
add_
item
(
"label_entity_id"
);
auto
&
struct_asym
=
db
[
"struct_asym"
];
struct_asym
.
add_
column
(
"entity_id"
);
struct_asym
.
add_
item
(
"entity_id"
);
std
::
map
<
std
::
string
,
std
::
vector
<
std
::
tuple
<
std
::
string
,
int
>>>
asyms
;
...
...
@@ -617,7 +617,7 @@ void comparePolySeqSchemes(datablock &db)
auto
&
ndb_poly_seq_scheme
=
db
[
"ndb_poly_seq_scheme"
];
auto
&
pdbx_poly_seq_scheme
=
db
[
"pdbx_poly_seq_scheme"
];
// Since often ndb_poly_seq_scheme only contains an id and mon_id
field
// Since often ndb_poly_seq_scheme only contains an id and mon_id
item
// we assume that it should match the accompanying pdbx_poly_seq
std
::
vector
<
std
::
string
>
asym_ids_ndb
,
asym_ids_pdbx
;
...
...
@@ -722,6 +722,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
std
::
vector
<
std
::
string
>
invalidCategories
;
// clean up each category
for
(
auto
&
cat
:
db
)
{
try
...
...
@@ -730,12 +731,12 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
if
(
not
cv
)
continue
;
// Start by renaming
column
s that may have old names based on alias info
// Start by renaming
item
s that may have old names based on alias info
for
(
auto
tag
:
cat
.
get_
column
s
())
for
(
auto
tag
:
cat
.
get_
item
s
())
{
auto
iv
=
cv
->
get_validator_for_item
(
tag
);
if
(
iv
)
// know, must be OK then
if
(
iv
)
// know, must be OK then
`
continue
;
iv
=
cv
->
get_validator_for_aliased_item
(
tag
);
...
...
@@ -744,7 +745,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Renaming "
<<
tag
<<
" to "
<<
iv
->
m_tag
<<
" in category "
<<
cat
.
name
()
<<
'\n'
;
cat
.
rename_
column
(
tag
,
iv
->
m_tag
);
cat
.
rename_
item
(
tag
,
iv
->
m_tag
);
}
for
(
auto
link
:
validator
.
get_links_for_child
(
cat
.
name
()))
...
...
@@ -767,14 +768,38 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
}
}
// Fill in all mandatory
field
s
for
(
auto
key
:
cv
->
m_mandatory_
field
s
)
// Fill in all mandatory
item
s
for
(
auto
key
:
cv
->
m_mandatory_
item
s
)
{
if
(
not
cat
.
has_
column
(
key
))
if
(
not
cat
.
has_
item
(
key
))
{
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Adding mandatory key "
<<
key
<<
" to category "
<<
cat
.
name
()
<<
'\n'
;
cat
.
add_column
(
key
);
cat
.
add_item
(
key
);
}
}
// validate all values, and if they do not validate replace the content with an unknown flag
for
(
auto
tag
:
cat
.
get_items
())
{
auto
iv
=
cv
->
get_validator_for_item
(
tag
);
if
(
not
iv
)
continue
;
auto
ix
=
cat
.
get_item_ix
(
tag
);
for
(
auto
row
:
cat
)
{
std
::
error_code
ec
;
std
::
string_view
value
=
row
[
ix
].
text
();
if
(
not
iv
->
validate_value
(
value
,
ec
))
{
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Replacing value ("
<<
std
::
quoted
(
value
)
<<
") for item "
<<
tag
<<
" since it does not validate
\n
"
;
row
[
ix
]
=
"?"
;
}
}
}
...
...
@@ -834,7 +859,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Attempt to fix "
<<
cat
.
name
()
<<
" failed: "
<<
ex
.
what
()
<<
'\n'
;
// replace
field
s that do not define a relation to a parent
// replace
item
s that do not define a relation to a parent
std
::
set
<
std
::
string
>
replaceableKeys
;
for
(
auto
key
:
cv
->
m_keys
)
...
...
src/pdb/validate-pdbx.cpp
View file @
2792caec
...
...
@@ -69,26 +69,67 @@ condition get_parents_condition(const validator &validator, row_handle rh, const
bool
is_valid_pdbx_file
(
const
file
&
file
,
std
::
string_view
dictionary
)
{
using
namespace
cif
::
literals
;
std
::
error_code
ec
;
bool
result
=
is_valid_pdbx_file
(
file
,
dictionary
,
ec
);
if
(
ec
!=
std
::
errc
())
throw
std
::
system_error
(
ec
);
return
result
;
}
bool
is_valid_pdbx_file
(
const
file
&
file
,
std
::
error_code
&
ec
)
{
bool
result
=
false
;
if
(
file
.
empty
())
ec
=
make_error_code
(
validation_error
::
empty_file
);
else
{
std
::
string
dictionary
=
"mmcif_pdbx"
;
for
(
auto
&
db
:
file
)
{
auto
audit_conform
=
db
.
get
(
"audit_conform"
);
if
(
audit_conform
==
nullptr
)
continue
;
if
(
not
audit_conform
->
empty
())
{
auto
specified_dict
=
audit_conform
->
front
()[
"dict_name"
];
if
(
not
specified_dict
.
empty
())
dictionary
=
specified_dict
.
as
<
std
::
string
>
();
}
auto
&
cf
=
cif
::
compound_factory
::
instance
();
auto
&
validator
=
cif
::
validator_factory
::
instance
().
operator
[](
dictionary
);
break
;
}
result
=
is_valid_pdbx_file
(
file
,
dictionary
,
ec
);
}
return
result
;
}
bool
is_valid_pdbx_file
(
const
file
&
file
,
std
::
string_view
dictionary
,
std
::
error_code
&
ec
)
{
using
namespace
cif
::
literals
;
bool
result
=
true
;
try
{
auto
&
cf
=
cif
::
compound_factory
::
instance
();
auto
&
validator
=
cif
::
validator_factory
::
instance
().
operator
[](
dictionary
);
if
(
file
.
empty
())
throw
validation
_error
(
"Empty file"
);
throw
std
::
runtime
_error
(
"Empty file"
);
auto
&
db
=
file
.
front
();
if
(
db
.
empty
())
throw
validation
_error
(
"Empty datablock"
);
throw
std
::
runtime
_error
(
"Empty datablock"
);
auto
&
atom_site
=
db
[
"atom_site"
];
if
(
atom_site
.
empty
())
throw
validation
_error
(
"Empty or missing atom_site category"
);
throw
std
::
runtime
_error
(
"Empty or missing atom_site category"
);
auto
&
pdbx_poly_seq_scheme
=
db
[
"pdbx_poly_seq_scheme"
];
...
...
@@ -111,29 +152,29 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
auto
p
=
pdbx_poly_seq_scheme
.
find
(
get_parents_condition
(
validator
,
r
,
pdbx_poly_seq_scheme
));
if
(
p
.
size
()
!=
1
)
throw
validation
_error
(
"For each residue in atom_site that is a residue in a polymer there should be exactly one pdbx_poly_seq_scheme record"
);
throw
std
::
runtime
_error
(
"For each residue in atom_site that is a residue in a polymer there should be exactly one pdbx_poly_seq_scheme record"
);
}
auto
&
entity
=
db
[
"entity"
];
if
(
entity
.
empty
())
throw
validation
_error
(
"Entity category is missing or empty"
);
throw
std
::
runtime
_error
(
"Entity category is missing or empty"
);
auto
&
entity_poly
=
db
[
"entity_poly"
];
if
(
entity_poly
.
empty
())
throw
validation
_error
(
"Entity_poly category is missing or empty"
);
throw
std
::
runtime
_error
(
"Entity_poly category is missing or empty"
);
auto
&
entity_poly_seq
=
db
[
"entity_poly_seq"
];
if
(
entity_poly_seq
.
empty
())
throw
validation
_error
(
"Entity_poly_seq category is missing or empty"
);
throw
std
::
runtime
_error
(
"Entity_poly_seq category is missing or empty"
);
auto
&
struct_asym
=
db
[
"struct_asym"
];
if
(
struct_asym
.
empty
())
throw
validation
_error
(
"struct_asym category is missing or empty"
);
throw
std
::
runtime
_error
(
"struct_asym category is missing or empty"
);
for
(
auto
entity_id
:
entity
.
find
<
std
::
string
>
(
"type"
_key
==
"polymer"
,
"id"
))
{
if
(
entity_poly
.
count
(
"entity_id"
_key
==
entity_id
)
!=
1
)
throw
validation
_error
(
"There should be exactly one entity_poly record per polymer entity"
);
throw
std
::
runtime
_error
(
"There should be exactly one entity_poly record per polymer entity"
);
const
auto
entity_poly_type
=
entity_poly
.
find1
<
std
::
string
>
(
"entity_id"
_key
==
entity_id
,
"type"
);
...
...
@@ -151,7 +192,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
"seq_id"
_key
==
num
and
"hetero"
_key
==
hetero
)
!=
1
)
{
throw
validation
_error
(
"For each entity_poly_seq record there should be exactly one pdbx_poly_seq record"
);
throw
std
::
runtime
_error
(
"For each entity_poly_seq record there should be exactly one pdbx_poly_seq record"
);
}
}
}
...
...
@@ -163,11 +204,11 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
"num"
_key
==
seq_id
and
"hetero"
_key
==
hetero
)
!=
1
)
{
throw
validation
_error
(
"For each pdbx_poly_seq/struct_asym record there should be exactly one entity_poly_seq record"
);
throw
std
::
runtime
_error
(
"For each pdbx_poly_seq/struct_asym record there should be exactly one entity_poly_seq record"
);
}
if
((
mon_per_seq_id
[
seq_id
].
size
()
>
1
)
!=
hetero
)
throw
validation
_error
(
"Mismatch between the hetero flag in the poly seq schemes and the number residues per seq_id"
);
throw
std
::
runtime
_error
(
"Mismatch between the hetero flag in the poly seq schemes and the number residues per seq_id"
);
}
for
(
const
auto
&
[
seq_id
,
mon_ids
]
:
mon_per_seq_id
)
...
...
@@ -184,7 +225,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
"label_seq_id"
_key
==
seq_id
and
not
std
::
move
(
cond
);
if
(
atom_site
.
contains
(
std
::
move
(
cond
)))
throw
validation
_error
(
"An atom_site record exists that has no parent in the poly seq scheme categories"
);
throw
std
::
runtime
_error
(
"An atom_site record exists that has no parent in the poly seq scheme categories"
);
}
}
...
...
@@ -250,7 +291,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
seq
->
erase
(
std
::
remove_if
(
seq
->
begin
(),
seq
->
end
(),
[](
char
ch
)
{
return
std
::
isspace
(
ch
);
}),
seq
->
end
());
if
(
not
seq_match
(
false
,
seq
->
begin
(),
seq
->
end
()))
throw
validation
_error
(
"Sequences do not match for entity "
+
entity_id
);
throw
std
::
runtime
_error
(
"Sequences do not match for entity "
+
entity_id
);
}
if
(
not
seq_can
.
has_value
())
...
...
@@ -263,7 +304,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
seq_can
->
erase
(
std
::
remove_if
(
seq_can
->
begin
(),
seq_can
->
end
(),
[](
char
ch
)
{
return
std
::
isspace
(
ch
);
}),
seq_can
->
end
());
if
(
not
seq_match
(
true
,
seq_can
->
begin
(),
seq_can
->
end
()))
throw
validation
_error
(
"Canonical sequences do not match for entity "
+
entity_id
);
throw
std
::
runtime
_error
(
"Canonical sequences do not match for entity "
+
entity_id
);
}
}
...
...
@@ -275,6 +316,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
result
=
false
;
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
ex
.
what
()
<<
'\n'
;
ec
=
make_error_code
(
validation_error
::
not_valid_pdbx
);
}
return
result
;
...
...
src/row.cpp
View file @
2792caec
...
...
@@ -29,44 +29,44 @@
namespace
cif
{
void
row_handle
::
assign
(
uint16_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
)
void
row_handle
::
assign
(
uint16_t
item
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
)
{
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
m_category
->
update_value
(
m_row
,
column
,
value
,
updateLinked
,
validate
);
m_category
->
update_value
(
m_row
,
item
,
value
,
updateLinked
,
validate
);
}
uint16_t
row_handle
::
get_
column
_ix
(
std
::
string_view
name
)
const
uint16_t
row_handle
::
get_
item
_ix
(
std
::
string_view
name
)
const
{
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
return
m_category
->
get_
column
_ix
(
name
);
return
m_category
->
get_
item
_ix
(
name
);
}
std
::
string_view
row_handle
::
get_
column
_name
(
uint16_t
ix
)
const
std
::
string_view
row_handle
::
get_
item
_name
(
uint16_t
ix
)
const
{
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
return
m_category
->
get_
column
_name
(
ix
);
return
m_category
->
get_
item
_name
(
ix
);
}
uint16_t
row_handle
::
add_
column
(
std
::
string_view
name
)
uint16_t
row_handle
::
add_
item
(
std
::
string_view
name
)
{
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
return
m_category
->
add_
column
(
name
);
return
m_category
->
add_
item
(
name
);
}
void
row_handle
::
swap
(
uint16_t
column
,
row_handle
&
b
)
void
row_handle
::
swap
(
uint16_t
item
,
row_handle
&
b
)
{
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
m_category
->
swap_item
(
column
,
*
this
,
b
);
m_category
->
swap_item
(
item
,
*
this
,
b
);
}
// --------------------------------------------------------------------
...
...
@@ -86,7 +86,7 @@ row_initializer::row_initializer(row_handle rh)
auto
&
i
=
r
->
operator
[](
ix
);
if
(
not
i
)
continue
;
emplace_back
(
cat
.
get_
column
_name
(
ix
),
i
.
text
());
emplace_back
(
cat
.
get_
item
_name
(
ix
),
i
.
text
());
}
}
...
...
src/validate.cpp
View file @
2792caec
...
...
@@ -39,10 +39,10 @@
// the code will use boost::regex instead.
#if USE_BOOST_REGEX
#include <boost/regex.hpp>
#
include <boost/regex.hpp>
using
boost
::
regex
;
#else
#include <regex>
#
include <regex>
using
std
::
regex
;
#endif
...
...
@@ -57,20 +57,11 @@ struct regex_impl : public regex
}
};
validation_error
::
validation_error
(
const
std
::
string
&
msg
)
:
m_msg
(
msg
)
{
}
validation_error
::
validation_error
(
const
std
::
string
&
cat
,
const
std
::
string
&
item
,
const
std
::
string
&
msg
)
:
m_msg
(
"When validating _"
+
cat
+
'.'
+
item
+
": "
+
msg
)
{
}
// --------------------------------------------------------------------
DDL_PrimitiveType
map_to_primitive_type
(
std
::
string_view
s
)
DDL_PrimitiveType
map_to_primitive_type
(
std
::
string_view
s
,
std
::
error_code
&
ec
)
noexcept
{
ec
=
{};
DDL_PrimitiveType
result
;
if
(
iequals
(
s
,
"char"
))
result
=
DDL_PrimitiveType
::
Char
;
...
...
@@ -79,7 +70,16 @@ DDL_PrimitiveType map_to_primitive_type(std::string_view s)
else
if
(
iequals
(
s
,
"numb"
))
result
=
DDL_PrimitiveType
::
Numb
;
else
throw
validation_error
(
"Not a known primitive type"
);
ec
=
make_error_code
(
validation_error
::
not_a_known_primitive_type
);
return
result
;
}
DDL_PrimitiveType
map_to_primitive_type
(
std
::
string_view
s
)
{
std
::
error_code
ec
;
auto
result
=
map_to_primitive_type
(
s
,
ec
);
if
(
ec
)
throw
std
::
system_error
(
ec
,
std
::
string
{
s
});
return
result
;
}
...
...
@@ -218,17 +218,24 @@ int type_validator::compare(std::string_view a, std::string_view b) const
void
item_validator
::
operator
()(
std
::
string_view
value
)
const
{
std
::
error_code
ec
;
if
(
not
validate_value
(
value
,
ec
))
throw
std
::
system_error
(
ec
,
std
::
string
{
value
}
+
" does not match rx for "
+
m_tag
);
}
bool
item_validator
::
validate_value
(
std
::
string_view
value
,
std
::
error_code
&
ec
)
const
noexcept
{
ec
=
{};
if
(
not
value
.
empty
()
and
value
!=
"?"
and
value
!=
"."
)
{
if
(
m_type
!=
nullptr
and
not
regex_match
(
value
.
begin
(),
value
.
end
(),
*
m_type
->
m_rx
))
throw
validation_error
(
m_category
->
m_name
,
m_tag
,
"Value '"
+
std
::
string
{
value
}
+
"' does not match type expression for type "
+
m_type
->
m_name
);
if
(
not
m_enums
.
empty
())
{
if
(
m_enums
.
count
(
std
::
string
{
value
})
==
0
)
throw
validation_error
(
m_category
->
m_name
,
m_tag
,
"Value '"
+
std
::
string
{
value
}
+
"' is not in the list of allowed values"
);
}
ec
=
make_error_code
(
validation_error
::
value_does_not_match_rx
);
else
if
(
not
m_enums
.
empty
()
and
m_enums
.
count
(
std
::
string
{
value
})
==
0
)
ec
=
make_error_code
(
validation_error
::
value_is_not_in_enumeration_list
);
}
return
ec
==
std
::
errc
();
}
// --------------------------------------------------------------------
...
...
@@ -236,7 +243,7 @@ void item_validator::operator()(std::string_view value) const
void
category_validator
::
add_item_validator
(
item_validator
&&
v
)
{
if
(
v
.
m_mandatory
)
m_mandatory_
field
s
.
insert
(
v
.
m_tag
);
m_mandatory_
item
s
.
insert
(
v
.
m_tag
);
v
.
m_category
=
this
;
...
...
@@ -265,7 +272,7 @@ const item_validator *category_validator::get_validator_for_aliased_item(std::st
for
(
auto
&
ai
:
iv
.
m_aliases
)
{
const
auto
&
[
cat
,
name
]
=
split_tag_name
(
ai
.
m_name
);
if
(
name
==
tag
and
cat
==
m_name
)
if
(
iequals
(
name
,
tag
)
and
iequals
(
cat
,
m_name
)
)
{
result
=
&
iv
;
break
;
...
...
@@ -373,7 +380,7 @@ std::vector<const link_validator *> validator::get_links_for_parent(std::string_
for
(
auto
&
l
:
m_link_validators
)
{
if
(
l
.
m_parent_category
==
category
)
if
(
iequals
(
l
.
m_parent_category
,
category
)
)
result
.
push_back
(
&
l
);
}
...
...
@@ -386,19 +393,41 @@ std::vector<const link_validator *> validator::get_links_for_child(std::string_v
for
(
auto
&
l
:
m_link_validators
)
{
if
(
l
.
m_child_category
==
category
)
if
(
iequals
(
l
.
m_child_category
,
category
)
)
result
.
push_back
(
&
l
);
}
return
result
;
}
void
validator
::
report_error
(
const
std
::
string
&
msg
,
bool
fatal
)
const
// void validator::report_error(const std::string &msg, bool fatal) const
// {
// if (m_strict or fatal)
// throw validation_error(msg);
// else if (VERBOSE > 0)
// std::cerr << msg << '\n';
// }
void
validator
::
report_error
(
std
::
error_code
ec
,
bool
fatal
)
const
{
if
(
m_strict
or
fatal
)
throw
validation_error
(
msg
);
else
if
(
VERBOSE
>
0
)
std
::
cerr
<<
msg
<<
'\n'
;
throw
std
::
system_error
(
ec
);
else
std
::
cerr
<<
ec
.
message
()
<<
'\n'
;
}
void
validator
::
report_error
(
std
::
error_code
ec
,
std
::
string_view
category
,
std
::
string_view
item
,
bool
fatal
)
const
{
std
::
ostringstream
os
;
os
<<
"category: "
<<
category
;
if
(
not
item
.
empty
())
os
<<
"; item: "
<<
item
;
if
(
m_strict
or
fatal
)
throw
std
::
system_error
(
ec
,
os
.
str
());
else
std
::
cerr
<<
ec
.
message
()
<<
": "
<<
os
.
str
()
<<
'\n'
;
}
// --------------------------------------------------------------------
...
...
@@ -460,12 +489,12 @@ const validator &validator_factory::operator[](std::string_view dictionary_name)
if
(
not
std
::
filesystem
::
exists
(
p
,
ec
)
or
ec
)
{
for
(
const
char
*
dir
:
{
#if defined(CACHE_DIR)
#
if defined(CACHE_DIR)
CACHE_DIR
,
#endif
#if defined(DATA_DIR)
#
endif
#
if defined(DATA_DIR)
DATA_DIR
#endif
#
endif
})
{
auto
p2
=
std
::
filesystem
::
path
(
dir
)
/
p
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment