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
30a2ebdb
Unverified
Commit
30a2ebdb
authored
Jan 23, 2024
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'github/develop-cif2fasta' into develop
parents
13ab1caf
a5d43998
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
1107 additions
and
761 deletions
+1107
-761
include/cif++/category.hpp
+215
-138
include/cif++/condition.hpp
+98
-89
include/cif++/datablock.hpp
+12
-3
include/cif++/item.hpp
+9
-9
include/cif++/iterator.hpp
+26
-26
include/cif++/model.hpp
+7
-7
include/cif++/parser.hpp
+11
-11
include/cif++/pdb.hpp
+41
-0
include/cif++/row.hpp
+41
-41
include/cif++/text.hpp
+14
-2
include/cif++/validate.hpp
+141
-22
src/category.cpp
+161
-162
src/condition.cpp
+10
-10
src/datablock.cpp
+37
-26
src/dictionary_parser.cpp
+27
-27
src/file.cpp
+4
-11
src/item.cpp
+5
-5
src/model.cpp
+4
-4
src/parser.cpp
+37
-37
src/pdb/pdb2cif_remark_3.cpp
+2
-2
src/pdb/reconstruct.cpp
+52
-27
src/pdb/validate-pdbx.cpp
+60
-18
src/row.cpp
+11
-11
src/text.cpp
+9
-9
src/validate.cpp
+73
-64
No files found.
include/cif++/category.hpp
View file @
30a2ebdb
...
...
@@ -71,7 +71,7 @@ class duplicate_key_error : public std::runtime_error
};
/// @brief A missing_key_error is thrown when an attempt is made
/// to create an index when one of the key
field
s is missing.
/// to create an index when one of the key
item
s is missing.
class
missing_key_error
:
public
std
::
runtime_error
{
public
:
...
...
@@ -156,8 +156,16 @@ class category
// --------------------------------------------------------------------
const
std
::
string
&
name
()
const
{
return
m_name
;
}
///< Returns the name of the category
iset
key_fields
()
const
;
///< Returns the cif::iset of key field names. Retrieved from the @ref category_validator for this category
std
::
set
<
uint16_t
>
key_field_indices
()
const
;
///< Returns a set of indices for the key fields.
[[
deprecated
(
"use key_items instead"
)]]
iset
key_fields
()
const
;
///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
iset
key_items
()
const
;
///< Returns the cif::iset of key item names. Retrieved from the @ref category_validator for this category
[[
deprecated
(
"use key_item_indices instead"
)]]
std
::
set
<
uint16_t
>
key_field_indices
()
const
;
///< Returns a set of indices for the key items.
std
::
set
<
uint16_t
>
key_item_indices
()
const
;
///< Returns a set of indices for the key items.
/// @brief Set the validator for this category to @a v
/// @param v The category_validator to assign. A nullptr value is allowed.
...
...
@@ -301,12 +309,12 @@ class category
using
key_type
=
row_initializer
;
/// @brief Return a row_handle for the row specified by \a key
/// @param key The value for the key,
field
s specified in the dictionary should have a value
/// @param key The value for the key,
item
s specified in the dictionary should have a value
/// @return The row found in the index, or an undefined row_handle
row_handle
operator
[](
const
key_type
&
key
);
/// @brief Return a const row_handle for the row specified by \a key
/// @param key The value for the key,
field
s specified in the dictionary should have a value
/// @param key The value for the key,
item
s specified in the dictionary should have a value
/// @return The row found in the index, or an undefined row_handle
const
row_handle
operator
[](
const
key_type
&
key
)
const
{
...
...
@@ -323,13 +331,13 @@ class category
/// std::cout << name << ": " << value << '\n';
/// @endcode
///
/// @tparam Ts The types for the
column
s requested
/// @param names The names for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
item
s requested
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
const
category
,
Ts
...
>
rows
(
Ns
...
names
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
column titl
es should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
item nam
es should be equal to the number of types to return"
);
return
iterator_proxy
<
const
category
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...
});
}
...
...
@@ -340,19 +348,19 @@ class category
/// for (const auto &[name, value] : cat.rows<std::string,int>("item_name", "item_value"))
/// std::cout << name << ": " << value << '\n';
///
/// // or in case we only need one
column
:
/// // or in case we only need one
item
:
///
/// for (int id : cat.rows<int>("id"))
/// std::cout << id << '\n';
/// @endcode
///
/// @tparam Ts The types for the
column
s requested
/// @param names The names for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
item
s requested
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
category
,
Ts
...
>
rows
(
Ns
...
names
)
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
column titl
es should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
item nam
es should be equal to the number of types to return"
);
return
iterator_proxy
<
category
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...
});
}
...
...
@@ -420,14 +428,14 @@ class category
/// @endcode
///
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @param names The names for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
category
,
Ts
...
>
find
(
condition
&&
cond
,
Ns
...
names
)
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
column titl
es should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
item nam
es should be equal to the number of types to return"
);
return
find
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...);
}
...
...
@@ -435,14 +443,14 @@ class category
/// iterator can be used in a structured binding context.
///
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @param names The names for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
const
category
,
Ts
...
>
find
(
condition
&&
cond
,
Ns
...
names
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
column titl
es should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
item nam
es should be equal to the number of types to return"
);
return
find
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...);
}
...
...
@@ -451,14 +459,14 @@ class category
///
/// @param pos Iterator pointing to the location where to start
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @param names The names for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
category
,
Ts
...
>
find
(
const_iterator
pos
,
condition
&&
cond
,
Ns
...
names
)
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
column titl
es should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
item nam
es should be equal to the number of types to return"
);
return
{
*
this
,
pos
,
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...
};
}
...
...
@@ -467,14 +475,14 @@ class category
///
/// @param pos Iterator pointing to the location where to start
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @param names The names for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
const
category
,
Ts
...
>
find
(
const_iterator
pos
,
condition
&&
cond
,
Ns
...
names
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
column titl
es should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of
item nam
es should be equal to the number of types to return"
);
return
{
*
this
,
pos
,
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...
};
}
...
...
@@ -529,30 +537,30 @@ class category
return
*
h
.
begin
();
}
/// @brief Return value for the
column named @a column
for the single row that
/// @brief Return value for the
item named @a item
for the single row that
/// matches @a cond. Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The type to use for the result
/// @param cond The condition to search for
/// @param
column The name of the column
to return the value for
/// @param
item The name of the item
to return the value for
/// @return The value found
template
<
typename
T
>
T
find1
(
condition
&&
cond
,
std
::
string_view
column
)
const
T
find1
(
condition
&&
cond
,
std
::
string_view
item
)
const
{
return
find1
<
T
>
(
cbegin
(),
std
::
move
(
cond
),
column
);
return
find1
<
T
>
(
cbegin
(),
std
::
move
(
cond
),
item
);
}
/// @brief Return value for the
column named @a column
for the single row that
/// @brief Return value for the
item named @a item
for the single row that
/// matches @a cond when starting to search at @a pos.
/// Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The type to use for the result
/// @param pos The location to start the search
/// @param cond The condition to search for
/// @param
column The name of the column
to return the value for
/// @param
item The name of the item
to return the value for
/// @return The value found
template
<
typename
T
,
std
::
enable_if_t
<
not
is_optional_v
<
T
>
,
int
>
=
0
>
T
find1
(
const_iterator
pos
,
condition
&&
cond
,
std
::
string_view
column
)
const
T
find1
(
const_iterator
pos
,
condition
&&
cond
,
std
::
string_view
item
)
const
{
auto
h
=
find
<
T
>
(
pos
,
std
::
move
(
cond
),
column
);
auto
h
=
find
<
T
>
(
pos
,
std
::
move
(
cond
),
item
);
if
(
h
.
size
()
!=
1
)
throw
multiple_results_error
();
...
...
@@ -560,18 +568,18 @@ class category
return
*
h
.
begin
();
}
/// @brief Return a value of type std::optional<T> for the
column named @a column
for the single row that
/// @brief Return a value of type std::optional<T> for the
item named @a item
for the single row that
/// matches @a cond when starting to search at @a pos.
/// If the row was not found, an empty value is returned.
/// @tparam The type to use for the result
/// @param pos The location to start the search
/// @param cond The condition to search for
/// @param
column The name of the column
to return the value for
/// @param
item The name of the item
to return the value for
/// @return The value found, can be empty if no row matches the condition
template
<
typename
T
,
std
::
enable_if_t
<
is_optional_v
<
T
>
,
int
>
=
0
>
T
find1
(
const_iterator
pos
,
condition
&&
cond
,
std
::
string_view
column
)
const
T
find1
(
const_iterator
pos
,
condition
&&
cond
,
std
::
string_view
item
)
const
{
auto
h
=
find
<
typename
T
::
value_type
>
(
pos
,
std
::
move
(
cond
),
column
);
auto
h
=
find
<
typename
T
::
value_type
>
(
pos
,
std
::
move
(
cond
),
item
);
if
(
h
.
size
()
>
1
)
throw
multiple_results_error
();
...
...
@@ -582,34 +590,34 @@ class category
return
*
h
.
begin
();
}
/// @brief Return a std::tuple for the values for the
columns named in @a column
s
/// @brief Return a std::tuple for the values for the
items named in @a item
s
/// for the single row that matches @a cond
/// Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The types to use for the resulting tuple
/// @param cond The condition to search for
/// @param
columns The names of the column
s to return the value for
/// @param
items The names of the item
s to return the value for
/// @return The values found as a single tuple of type std::tuple<Ts...>
template
<
typename
...
Ts
,
typename
...
Cs
,
typename
U
=
std
::
enable_if_t
<
sizeof
...(
Ts
)
!=
1
>>
std
::
tuple
<
Ts
...
>
find1
(
condition
&&
cond
,
Cs
...
column
s
)
const
std
::
tuple
<
Ts
...
>
find1
(
condition
&&
cond
,
Cs
...
item
s
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
column titl
es should be equal to the number of types to return"
);
// static_assert(std::is_same_v<Cs, const char*>..., "The
column
names should be const char");
return
find1
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
column
s
)...);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
item nam
es should be equal to the number of types to return"
);
// static_assert(std::is_same_v<Cs, const char*>..., "The
item
names should be const char");
return
find1
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
item
s
)...);
}
/// @brief Return a std::tuple for the values for the
columns named in @a column
s
/// @brief Return a std::tuple for the values for the
items named in @a item
s
/// for the single row that matches @a cond when starting to search at @a pos
/// Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The types to use for the resulting tuple
/// @param pos The location to start the search
/// @param cond The condition to search for
/// @param
columns The names of the column
s to return the value for
/// @param
items The names of the item
s to return the value for
/// @return The values found as a single tuple of type std::tuple<Ts...>
template
<
typename
...
Ts
,
typename
...
Cs
,
typename
U
=
std
::
enable_if_t
<
sizeof
...(
Ts
)
!=
1
>>
std
::
tuple
<
Ts
...
>
find1
(
const_iterator
pos
,
condition
&&
cond
,
Cs
...
column
s
)
const
std
::
tuple
<
Ts
...
>
find1
(
const_iterator
pos
,
condition
&&
cond
,
Cs
...
item
s
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
column titl
es should be equal to the number of types to return"
);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
column
s
)...);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
item nam
es should be equal to the number of types to return"
);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
item
s
)...);
if
(
h
.
size
()
!=
1
)
throw
multiple_results_error
();
...
...
@@ -658,74 +666,74 @@ class category
return
h
.
empty
()
?
row_handle
{}
:
*
h
.
begin
();
}
/// @brief Return the value for
column @a column
for the first row that matches condition @a cond
/// @brief Return the value for
item @a item
for the first row that matches condition @a cond
/// @tparam The type of the value to return
/// @param cond The condition to search for
/// @param
column The column
for which the value should be returned
/// @param
item The item
for which the value should be returned
/// @return The value found or a default constructed value if not found
template
<
typename
T
>
T
find_first
(
condition
&&
cond
,
std
::
string_view
column
)
const
T
find_first
(
condition
&&
cond
,
std
::
string_view
item
)
const
{
return
find_first
<
T
>
(
cbegin
(),
std
::
move
(
cond
),
column
);
return
find_first
<
T
>
(
cbegin
(),
std
::
move
(
cond
),
item
);
}
/// @brief Return the value for
column @a column
for the first row that matches condition @a cond
/// @brief Return the value for
item @a item
for the first row that matches condition @a cond
/// when starting the search at @a pos
/// @tparam The type of the value to return
/// @param pos The location to start searching
/// @param cond The condition to search for
/// @param
column The column
for which the value should be returned
/// @param
item The item
for which the value should be returned
/// @return The value found or a default constructed value if not found
template
<
typename
T
>
T
find_first
(
const_iterator
pos
,
condition
&&
cond
,
std
::
string_view
column
)
const
T
find_first
(
const_iterator
pos
,
condition
&&
cond
,
std
::
string_view
item
)
const
{
auto
h
=
find
<
T
>
(
pos
,
std
::
move
(
cond
),
column
);
auto
h
=
find
<
T
>
(
pos
,
std
::
move
(
cond
),
item
);
return
h
.
empty
()
?
T
{}
:
*
h
.
begin
();
}
/// @brief Return a tuple containing the values for the
columns @a column
s for the first row that matches condition @a cond
/// @brief Return a tuple containing the values for the
items @a item
s for the first row that matches condition @a cond
/// @tparam The types of the values to return
/// @param cond The condition to search for
/// @param
columns The column
s for which the values should be returned
/// @param
items The item
s for which the values should be returned
/// @return The values found or default constructed values if not found
template
<
typename
...
Ts
,
typename
...
Cs
,
typename
U
=
std
::
enable_if_t
<
sizeof
...(
Ts
)
!=
1
>>
std
::
tuple
<
Ts
...
>
find_first
(
condition
&&
cond
,
Cs
...
column
s
)
const
std
::
tuple
<
Ts
...
>
find_first
(
condition
&&
cond
,
Cs
...
item
s
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
column titl
es should be equal to the number of types to return"
);
// static_assert(std::is_same_v<Cs, const char*>..., "The
column
names should be const char");
return
find_first
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
column
s
)...);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
item nam
es should be equal to the number of types to return"
);
// static_assert(std::is_same_v<Cs, const char*>..., "The
item
names should be const char");
return
find_first
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
item
s
)...);
}
/// @brief Return a tuple containing the values for the
columns @a column
s for the first row that matches condition @a cond
/// @brief Return a tuple containing the values for the
items @a item
s for the first row that matches condition @a cond
/// when starting the search at @a pos
/// @tparam The types of the values to return
/// @param pos The location to start searching
/// @param cond The condition to search for
/// @param
columns The column
s for which the values should be returned
/// @param
items The item
s for which the values should be returned
/// @return The values found or default constructed values if not found
template
<
typename
...
Ts
,
typename
...
Cs
,
typename
U
=
std
::
enable_if_t
<
sizeof
...(
Ts
)
!=
1
>>
std
::
tuple
<
Ts
...
>
find_first
(
const_iterator
pos
,
condition
&&
cond
,
Cs
...
column
s
)
const
std
::
tuple
<
Ts
...
>
find_first
(
const_iterator
pos
,
condition
&&
cond
,
Cs
...
item
s
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
column titl
es should be equal to the number of types to return"
);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
column
s
)...);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of
item nam
es should be equal to the number of types to return"
);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
item
s
)...);
return
h
.
empty
()
?
std
::
tuple
<
Ts
...
>
{}
:
*
h
.
begin
();
}
// --------------------------------------------------------------------
/// @brief Return the maximum value for
column @a column
for all rows that match condition @a cond
/// @brief Return the maximum value for
item @a item
for all rows that match condition @a cond
/// @tparam The type of the value to return
/// @param
column The column
to use for the value
/// @param
item The item
to use for the value
/// @param cond The condition to search for
/// @return The value found or the minimal value for the type
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
T
find_max
(
std
::
string_view
column
,
condition
&&
cond
)
const
T
find_max
(
std
::
string_view
item
,
condition
&&
cond
)
const
{
T
result
=
std
::
numeric_limits
<
T
>::
min
();
for
(
auto
v
:
find
<
T
>
(
std
::
move
(
cond
),
column
))
for
(
auto
v
:
find
<
T
>
(
std
::
move
(
cond
),
item
))
{
if
(
result
<
v
)
result
=
v
;
...
...
@@ -734,27 +742,27 @@ class category
return
result
;
}
/// @brief Return the maximum value for
column @a column
for all rows
/// @brief Return the maximum value for
item @a item
for all rows
/// @tparam The type of the value to return
/// @param
column The column
to use for the value
/// @param
item The item
to use for the value
/// @return The value found or the minimal value for the type
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
T
find_max
(
std
::
string_view
column
)
const
T
find_max
(
std
::
string_view
item
)
const
{
return
find_max
<
T
>
(
column
,
all
());
return
find_max
<
T
>
(
item
,
all
());
}
/// @brief Return the minimum value for
column @a column
for all rows that match condition @a cond
/// @brief Return the minimum value for
item @a item
for all rows that match condition @a cond
/// @tparam The type of the value to return
/// @param
column The column
to use for the value
/// @param
item The item
to use for the value
/// @param cond The condition to search for
/// @return The value found or the maximum value for the type
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
T
find_min
(
std
::
string_view
column
,
condition
&&
cond
)
const
T
find_min
(
std
::
string_view
item
,
condition
&&
cond
)
const
{
T
result
=
std
::
numeric_limits
<
T
>::
max
();
for
(
auto
v
:
find
<
T
>
(
std
::
move
(
cond
),
column
))
for
(
auto
v
:
find
<
T
>
(
std
::
move
(
cond
),
item
))
{
if
(
result
>
v
)
result
=
v
;
...
...
@@ -763,14 +771,14 @@ class category
return
result
;
}
/// @brief Return the maximum value for
column @a column
for all rows
/// @brief Return the maximum value for
item @a item
for all rows
/// @tparam The type of the value to return
/// @param
column The column
to use for the value
/// @param
item The item
to use for the value
/// @return The value found or the maximum value for the type
template
<
typename
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>
,
int
>
=
0
>
T
find_min
(
std
::
string_view
column
)
const
T
find_min
(
std
::
string_view
item
)
const
{
return
find_min
<
T
>
(
column
,
all
());
return
find_min
<
T
>
(
item
,
all
());
}
/// @brief Return whether a row exists that matches condition @a cond
...
...
@@ -918,7 +926,7 @@ class category
for
(
auto
i
=
b
;
i
!=
e
;
++
i
)
{
// item_value *new_item = this->create_item(*i);
r
->
append
(
add_
column
(
i
->
name
()),
{
i
->
value
()
});
r
->
append
(
add_
item
(
i
->
name
()),
{
i
->
value
()
});
}
}
catch
(...)
...
...
@@ -949,111 +957,172 @@ class category
{
return
prefix
+
std
::
to_string
(
nr
+
1
);
});
}
/// @brief Generate a new, unique value for a item named @a
tag
/// @param
tag
The name of the item
/// @brief Generate a new, unique value for a item named @a
item_name
/// @param
item_name
The name of the item
/// @return a new unique value
std
::
string
get_unique_value
(
std
::
string_view
tag
);
std
::
string
get_unique_value
(
std
::
string_view
item_name
);
// --------------------------------------------------------------------
/// \brief Update a single
column named @a tag
in the rows that match \a cond to value \a value
/// \brief Update a single
item named @a item_name
in the rows that match \a cond to value \a value
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
void
update_value
(
condition
&&
cond
,
std
::
string_view
tag
,
std
::
string_view
value
)
void
update_value
(
condition
&&
cond
,
std
::
string_view
item_name
,
std
::
string_view
value
)
{
auto
rs
=
find
(
std
::
move
(
cond
));
std
::
vector
<
row_handle
>
rows
;
std
::
copy
(
rs
.
begin
(),
rs
.
end
(),
std
::
back_inserter
(
rows
));
update_value
(
rows
,
tag
,
value
);
update_value
(
rows
,
item_name
,
value
);
}
/// \brief Update a single
column named @a tag
in @a rows to value \a value
/// \brief Update a single
item named @a item_name
in @a rows to value \a value
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
void
update_value
(
const
std
::
vector
<
row_handle
>
&
rows
,
std
::
string_view
tag
,
std
::
string_view
value
);
void
update_value
(
const
std
::
vector
<
row_handle
>
&
rows
,
std
::
string_view
item_name
,
std
::
string_view
value
);
// --------------------------------------------------------------------
/// \brief Return the index number for \a column_name
// Naming used to be very inconsistent. For backward compatibility,
// the old function names are here as deprecated variants.
/// \brief Return the index number for \a column_name
[[
deprecated
(
"Use get_item_ix instead"
)]]
uint16_t
get_column_ix
(
std
::
string_view
column_name
)
const
{
return
get_item_ix
(
column_name
);
}
/// @brief Return the name for column with index @a ix
/// @param ix The index number
/// @return The name of the column
[[
deprecated
(
"use get_item_name instead"
)]]
std
::
string_view
get_column_name
(
uint16_t
ix
)
const
{
return
get_item_name
(
ix
);
}
/// @brief Make sure a item with name @a item_name is known and return its index number
/// @param item_name The name of the item
/// @return The index number of the item
[[
deprecated
(
"use add_item instead"
)]]
uint16_t
add_column
(
std
::
string_view
item_name
)
{
return
add_item
(
item_name
);
}
/** @brief Remove column name @a colum_name
* @param column_name The column to be removed
*/
[[
deprecated
(
"use remove_item instead"
)]]
void
remove_column
(
std
::
string_view
column_name
)
{
remove_item
(
column_name
);
}
/** @brief Rename column @a from_name to @a to_name */
[[
deprecated
(
"use rename_item instead"
)]]
void
rename_column
(
std
::
string_view
from_name
,
std
::
string_view
to_name
)
{
rename_item
(
from_name
,
to_name
);
}
/// @brief Return whether a column with name @a name exists in this category
/// @param name The name of the column
/// @return True if the column exists
[[
deprecated
(
"use has_item instead"
)]]
bool
has_column
(
std
::
string_view
name
)
const
{
return
has_item
(
name
);
}
/// @brief Return the cif::iset of columns in this category
[[
deprecated
(
"use get_items instead"
)]]
iset
get_columns
()
const
{
return
get_items
();
}
// --------------------------------------------------------------------
/// \brief Return the index number for \a item_name
uint16_t
get_item_ix
(
std
::
string_view
item_name
)
const
{
uint16_t
result
;
for
(
result
=
0
;
result
<
m_
column
s
.
size
();
++
result
)
for
(
result
=
0
;
result
<
m_
item
s
.
size
();
++
result
)
{
if
(
iequals
(
column_name
,
m_column
s
[
result
].
m_name
))
if
(
iequals
(
item_name
,
m_item
s
[
result
].
m_name
))
break
;
}
if
(
VERBOSE
>
0
and
result
==
m_
column
s
.
size
()
and
m_cat_validator
!=
nullptr
)
// validate the name, if it is known at all (since it was not found)
if
(
VERBOSE
>
0
and
result
==
m_
item
s
.
size
()
and
m_cat_validator
!=
nullptr
)
// validate the name, if it is known at all (since it was not found)
{
auto
iv
=
m_cat_validator
->
get_validator_for_item
(
column
_name
);
auto
iv
=
m_cat_validator
->
get_validator_for_item
(
item
_name
);
if
(
iv
==
nullptr
)
std
::
cerr
<<
"Invalid name used '"
<<
column_name
<<
"' is not a known column
in "
+
m_name
<<
'\n'
;
std
::
cerr
<<
"Invalid name used '"
<<
item_name
<<
"' is not a known item
in "
+
m_name
<<
'\n'
;
}
return
result
;
}
/// @brief Return the name for
column
with index @a ix
/// @brief Return the name for
item
with index @a ix
/// @param ix The index number
/// @return The name of the
column
std
::
string_view
get_
column
_name
(
uint16_t
ix
)
const
/// @return The name of the
item
std
::
string_view
get_
item
_name
(
uint16_t
ix
)
const
{
if
(
ix
>=
m_
column
s
.
size
())
throw
std
::
out_of_range
(
"
column
index is out of range"
);
if
(
ix
>=
m_
item
s
.
size
())
throw
std
::
out_of_range
(
"
item
index is out of range"
);
return
m_
column
s
[
ix
].
m_name
;
return
m_
item
s
[
ix
].
m_name
;
}
/// @brief Make sure a
column with name @a column
_name is known and return its index number
/// @param
column_name The name of the column
/// @return The index number of the
column
uint16_t
add_
column
(
std
::
string_view
column
_name
)
/// @brief Make sure a
item with name @a item
_name is known and return its index number
/// @param
item_name The name of the item
/// @return The index number of the
item
uint16_t
add_
item
(
std
::
string_view
item
_name
)
{
using
namespace
std
::
literals
;
uint16_t
result
=
get_
column_ix
(
column
_name
);
uint16_t
result
=
get_
item_ix
(
item
_name
);
if
(
result
==
m_
column
s
.
size
())
if
(
result
==
m_
item
s
.
size
())
{
const
item_validator
*
item_validator
=
nullptr
;
if
(
m_cat_validator
!=
nullptr
)
{
item_validator
=
m_cat_validator
->
get_validator_for_item
(
column
_name
);
item_validator
=
m_cat_validator
->
get_validator_for_item
(
item
_name
);
if
(
item_validator
==
nullptr
)
m_validator
->
report_error
(
"tag "
+
std
::
string
(
column_name
)
+
" not allowed in category "
+
m_name
,
false
);
m_validator
->
report_error
(
validation_error
::
item_not_allowed_in_category
,
m_name
,
ite
m_name
,
false
);
}
m_
columns
.
emplace_back
(
column
_name
,
item_validator
);
m_
items
.
emplace_back
(
item
_name
,
item_validator
);
}
return
result
;
}
/** @brief Remove
column
name @a colum_name
* @param
column_name The column
to be removed
/** @brief Remove
item
name @a colum_name
* @param
item_name The item
to be removed
*/
void
remove_
column
(
std
::
string_view
column
_name
);
void
remove_
item
(
std
::
string_view
item
_name
);
/** @brief Rename
column
@a from_name to @a to_name */
void
rename_
column
(
std
::
string_view
from_name
,
std
::
string_view
to_name
);
/** @brief Rename
item
@a from_name to @a to_name */
void
rename_
item
(
std
::
string_view
from_name
,
std
::
string_view
to_name
);
/// @brief Return whether a
column
with name @a name exists in this category
/// @param name The name of the
column
/// @return True if the
column
exists
bool
has_
column
(
std
::
string_view
name
)
const
/// @brief Return whether a
item
with name @a name exists in this category
/// @param name The name of the
item
/// @return True if the
item
exists
bool
has_
item
(
std
::
string_view
name
)
const
{
return
get_
column_ix
(
name
)
<
m_column
s
.
size
();
return
get_
item_ix
(
name
)
<
m_item
s
.
size
();
}
/// @brief Return the cif::iset of
column
s in this category
iset
get_
column
s
()
const
;
/// @brief Return the cif::iset of
item
s in this category
iset
get_
item
s
()
const
;
// --------------------------------------------------------------------
...
...
@@ -1069,23 +1138,31 @@ class category
// --------------------------------------------------------------------
/// This function returns effectively the list of fully qualified column
/// names, that is category_name + '.' + column_name for each column
std
::
vector
<
std
::
string
>
get_tag_order
()
const
;
/// This function returns effectively the list of fully qualified item
/// names, that is category_name + '.' + item_name for each item
[[
deprecated
(
"use get_item_order instead"
)]]
std
::
vector
<
std
::
string
>
get_tag_order
()
const
{
return
get_item_order
();
}
/// This function returns effectively the list of fully qualified item
/// names, that is category_name + '.' + item_name for each item
std
::
vector
<
std
::
string
>
get_item_order
()
const
;
/// Write the contents of the category to the std::ostream @a os
void
write
(
std
::
ostream
&
os
)
const
;
/// @brief Write the contents of the category to the std::ostream @a os and
/// use @a order as the order of the
columns. If @a addMissingColumn
s is
/// false,
column
s that do not contain any value will be suppressed
/// use @a order as the order of the
items. If @a addMissingItem
s is
/// false,
item
s that do not contain any value will be suppressed
/// @param os The std::ostream to write to
/// @param order The order in which the
column
s should appear
/// @param addMissing
Columns When false, empty column
s are suppressed from the output
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
,
bool
addMissing
Column
s
=
true
);
/// @param order The order in which the
item
s should appear
/// @param addMissing
Items When false, empty item
s are suppressed from the output
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
,
bool
addMissing
Item
s
=
true
);
private
:
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
uint16_t
>
&
order
,
bool
includeEmpty
Column
s
)
const
;
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
uint16_t
>
&
order
,
bool
includeEmpty
Item
s
)
const
;
public
:
/// friend function to make it possible to do:
...
...
@@ -1099,7 +1176,7 @@ class category
}
private
:
void
update_value
(
row
*
row
,
uint16_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
void
update_value
(
row
*
row
,
uint16_t
item
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
void
erase_orphans
(
condition
&&
cond
,
category
&
parent
);
...
...
@@ -1136,12 +1213,12 @@ class category
row_handle
create_copy
(
row_handle
r
);
struct
item_
column
struct
item_
entry
{
std
::
string
m_name
;
const
item_validator
*
m_validator
;
item_
column
(
std
::
string_view
name
,
const
item_validator
*
validator
)
item_
entry
(
std
::
string_view
name
,
const
item_validator
*
validator
)
:
m_name
(
name
)
,
m_validator
(
validator
)
{
...
...
@@ -1171,12 +1248,12 @@ class category
// --------------------------------------------------------------------
void
swap_item
(
uint16_t
column
_ix
,
row_handle
&
a
,
row_handle
&
b
);
void
swap_item
(
uint16_t
item
_ix
,
row_handle
&
a
,
row_handle
&
b
);
// --------------------------------------------------------------------
std
::
string
m_name
;
std
::
vector
<
item_
column
>
m_column
s
;
std
::
vector
<
item_
entry
>
m_item
s
;
const
validator
*
m_validator
=
nullptr
;
const
category_validator
*
m_cat_validator
=
nullptr
;
std
::
vector
<
link
>
m_parent_links
,
m_child_links
;
...
...
include/cif++/condition.hpp
View file @
30a2ebdb
...
...
@@ -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
*/
...
...
@@ -305,14 +314,14 @@ namespace detail
{
struct
key_is_empty_condition_impl
:
public
condition_impl
{
key_is_empty_condition_impl
(
const
std
::
string
&
item_
tag
)
:
m_item_
tag
(
item_tag
)
key_is_empty_condition_impl
(
const
std
::
string
&
item_
name
)
:
m_item_
name
(
item_name
)
{
}
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_name
);
return
this
;
}
...
...
@@ -323,23 +332,23 @@ namespace detail
void
str
(
std
::
ostream
&
os
)
const
override
{
os
<<
m_item_
tag
<<
" IS NULL"
;
os
<<
m_item_
name
<<
" IS NULL"
;
}
std
::
string
m_item_
tag
;
std
::
string
m_item_
name
;
uint16_t
m_item_ix
=
0
;
};
struct
key_is_not_empty_condition_impl
:
public
condition_impl
{
key_is_not_empty_condition_impl
(
const
std
::
string
&
item_
tag
)
:
m_item_
tag
(
item_tag
)
key_is_not_empty_condition_impl
(
const
std
::
string
&
item_
name
)
:
m_item_
name
(
item_name
)
{
}
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_name
);
return
this
;
}
...
...
@@ -350,17 +359,17 @@ namespace detail
void
str
(
std
::
ostream
&
os
)
const
override
{
os
<<
m_item_
tag
<<
" IS NOT NULL"
;
os
<<
m_item_
name
<<
" IS NOT NULL"
;
}
std
::
string
m_item_
tag
;
std
::
string
m_item_
name
;
uint16_t
m_item_ix
=
0
;
};
struct
key_equals_condition_impl
:
public
condition_impl
{
key_equals_condition_impl
(
item
&&
i
)
:
m_item_
tag
(
i
.
name
())
:
m_item_
name
(
i
.
name
())
,
m_value
(
i
.
value
())
{
}
...
...
@@ -374,7 +383,7 @@ namespace detail
void
str
(
std
::
ostream
&
os
)
const
override
{
os
<<
m_item_
tag
<<
(
m_icase
?
"^ "
:
" "
)
<<
" == "
<<
m_value
;
os
<<
m_item_
name
<<
(
m_icase
?
"^ "
:
" "
)
<<
" == "
<<
m_value
;
}
virtual
std
::
optional
<
row_handle
>
single
()
const
override
...
...
@@ -390,13 +399,13 @@ namespace detail
if
(
m_single_hit
.
has_value
()
or
ri
->
m_single_hit
.
has_value
())
return
m_single_hit
==
ri
->
m_single_hit
;
else
// watch out, both m_item_ix might be the same while
tag
s might be diffent (in case they both do not exist in the category)
return
m_item_ix
==
ri
->
m_item_ix
and
m_value
==
ri
->
m_value
and
m_item_
tag
==
ri
->
m_item_tag
;
// watch out, both m_item_ix might be the same while
item_name
s might be diffent (in case they both do not exist in the category)
return
m_item_ix
==
ri
->
m_item_ix
and
m_value
==
ri
->
m_value
and
m_item_
name
==
ri
->
m_item_name
;
}
return
this
==
rhs
;
}
std
::
string
m_item_
tag
;
std
::
string
m_item_
name
;
uint16_t
m_item_ix
=
0
;
bool
m_icase
=
false
;
std
::
string
m_value
;
...
...
@@ -406,7 +415,7 @@ namespace detail
struct
key_equals_or_empty_condition_impl
:
public
condition_impl
{
key_equals_or_empty_condition_impl
(
key_equals_condition_impl
*
equals
)
:
m_item_
tag
(
equals
->
m_item_tag
)
:
m_item_
name
(
equals
->
m_item_name
)
,
m_value
(
equals
->
m_value
)
,
m_icase
(
equals
->
m_icase
)
,
m_single_hit
(
equals
->
m_single_hit
)
...
...
@@ -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_name
);
m_icase
=
is_
item_type_uchar
(
c
,
m_item_name
);
return
this
;
}
...
...
@@ -432,7 +441,7 @@ namespace detail
void
str
(
std
::
ostream
&
os
)
const
override
{
os
<<
'('
<<
m_item_
tag
<<
(
m_icase
?
"^ "
:
" "
)
<<
" == "
<<
m_value
<<
" OR "
<<
m_item_tag
<<
" IS NULL)"
;
os
<<
'('
<<
m_item_
name
<<
(
m_icase
?
"^ "
:
" "
)
<<
" == "
<<
m_value
<<
" OR "
<<
m_item_name
<<
" IS NULL)"
;
}
virtual
std
::
optional
<
row_handle
>
single
()
const
override
...
...
@@ -448,13 +457,13 @@ namespace detail
if
(
m_single_hit
.
has_value
()
or
ri
->
m_single_hit
.
has_value
())
return
m_single_hit
==
ri
->
m_single_hit
;
else
// watch out, both m_item_ix might be the same while
tag
s might be diffent (in case they both do not exist in the category)
return
m_item_ix
==
ri
->
m_item_ix
and
m_value
==
ri
->
m_value
and
m_item_
tag
==
ri
->
m_item_tag
;
// watch out, both m_item_ix might be the same while
item_name
s might be diffent (in case they both do not exist in the category)
return
m_item_ix
==
ri
->
m_item_ix
and
m_value
==
ri
->
m_value
and
m_item_
name
==
ri
->
m_item_name
;
}
return
this
==
rhs
;
}
std
::
string
m_item_
tag
;
std
::
string
m_item_
name
;
uint16_t
m_item_ix
=
0
;
std
::
string
m_value
;
bool
m_icase
=
false
;
...
...
@@ -464,8 +473,8 @@ namespace detail
struct
key_compare_condition_impl
:
public
condition_impl
{
template
<
typename
COMP
>
key_compare_condition_impl
(
const
std
::
string
&
item_
tag
,
COMP
&&
comp
,
const
std
::
string
&
s
)
:
m_item_
tag
(
item_tag
)
key_compare_condition_impl
(
const
std
::
string
&
item_
name
,
COMP
&&
comp
,
const
std
::
string
&
s
)
:
m_item_
name
(
item_name
)
,
m_compare
(
std
::
move
(
comp
))
,
m_str
(
s
)
{
...
...
@@ -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_name
);
m_icase
=
is_
item_type_uchar
(
c
,
m_item_name
);
return
this
;
}
...
...
@@ -485,10 +494,10 @@ namespace detail
void
str
(
std
::
ostream
&
os
)
const
override
{
os
<<
m_item_
tag
<<
(
m_icase
?
"^ "
:
" "
)
<<
m_str
;
os
<<
m_item_
name
<<
(
m_icase
?
"^ "
:
" "
)
<<
m_str
;
}
std
::
string
m_item_
tag
;
std
::
string
m_item_
name
;
uint16_t
m_item_ix
=
0
;
bool
m_icase
=
false
;
std
::
function
<
bool
(
row_handle
,
bool
)
>
m_compare
;
...
...
@@ -497,8 +506,8 @@ namespace detail
struct
key_matches_condition_impl
:
public
condition_impl
{
key_matches_condition_impl
(
const
std
::
string
&
item_
tag
,
const
std
::
regex
&
rx
)
:
m_item_
tag
(
item_tag
)
key_matches_condition_impl
(
const
std
::
string
&
item_
name
,
const
std
::
regex
&
rx
)
:
m_item_
name
(
item_name
)
,
m_item_ix
(
0
)
,
mRx
(
rx
)
{
...
...
@@ -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_name
);
return
this
;
}
...
...
@@ -518,10 +527,10 @@ namespace detail
void
str
(
std
::
ostream
&
os
)
const
override
{
os
<<
m_item_
tag
<<
" =~ expression"
;
os
<<
m_item_
name
<<
" =~ expression"
;
}
std
::
string
m_item_
tag
;
std
::
string
m_item_
name
;
uint16_t
m_item_ix
;
std
::
regex
mRx
;
};
...
...
@@ -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
{
...
...
@@ -864,7 +873,7 @@ inline condition operator or(condition &&a, condition &&b)
auto
ci
=
static_cast
<
detail
::
key_equals_condition_impl
*>
(
a
.
m_impl
);
auto
ce
=
static_cast
<
detail
::
key_is_empty_condition_impl
*>
(
b
.
m_impl
);
if
(
ci
->
m_item_
tag
==
ce
->
m_item_tag
)
if
(
ci
->
m_item_
name
==
ce
->
m_item_name
)
return
condition
(
new
detail
::
key_equals_or_empty_condition_impl
(
ci
));
}
else
if
(
typeid
(
*
b
.
m_impl
)
==
typeid
(
detail
::
key_equals_condition_impl
)
and
...
...
@@ -873,7 +882,7 @@ inline condition operator or(condition &&a, condition &&b)
auto
ci
=
static_cast
<
detail
::
key_equals_condition_impl
*>
(
b
.
m_impl
);
auto
ce
=
static_cast
<
detail
::
key_is_empty_condition_impl
*>
(
a
.
m_impl
);
if
(
ci
->
m_item_
tag
==
ce
->
m_item_tag
)
if
(
ci
->
m_item_
name
==
ce
->
m_item_name
)
return
condition
(
new
detail
::
key_equals_or_empty_condition_impl
(
ci
));
}
...
...
@@ -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,45 +918,45 @@ 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
{
/**
* @brief Construct a new key object using @a item
Tag
as name
* @brief Construct a new key object using @a item
_name
as name
*
* @param item
Tag
* @param item
_name
*/
explicit
key
(
const
std
::
string
&
item
Tag
)
:
m_item_
tag
(
itemTag
)
explicit
key
(
const
std
::
string
&
item
_name
)
:
m_item_
name
(
item_name
)
{
}
/**
* @brief Construct a new key object using @a item
Tag
as name
* @brief Construct a new key object using @a item
_name
as name
*
* @param item
Tag
* @param item
_name
*/
explicit
key
(
const
char
*
item
Tag
)
:
m_item_
tag
(
itemTag
)
explicit
key
(
const
char
*
item
_name
)
:
m_item_
name
(
item_name
)
{
}
/**
* @brief Construct a new key object using @a item
Tag
as name
* @brief Construct a new key object using @a item
_name
as name
*
* @param item
Tag
* @param item
_name
*/
explicit
key
(
std
::
string_view
item
Tag
)
:
m_item_
tag
(
itemTag
)
explicit
key
(
std
::
string_view
item
_name
)
:
m_item_
name
(
item_name
)
{
}
key
(
const
key
&
)
=
delete
;
key
&
operator
=
(
const
key
&
)
=
delete
;
std
::
string
m_item_
tag
;
///< The column
name
std
::
string
m_item_
name
;
///< The item
name
};
/**
...
...
@@ -956,7 +965,7 @@ struct key
template
<
typename
T
>
condition
operator
==
(
const
key
&
key
,
const
T
&
v
)
{
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_
tag
,
v
}));
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_
name
,
v
}));
}
/**
...
...
@@ -965,9 +974,9 @@ condition operator==(const key &key, const T &v)
inline
condition
operator
==
(
const
key
&
key
,
std
::
string_view
value
)
{
if
(
not
value
.
empty
())
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_
tag
,
value
}));
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_
name
,
value
}));
else
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_
tag
));
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_
name
));
}
/**
...
...
@@ -997,8 +1006,8 @@ condition operator>(const key &key, const T &v)
s
<<
" > "
<<
v
;
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_
tag
,
[
tag
=
key
.
m_item_tag
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
},
key
.
m_item_
name
,
[
item_name
=
key
.
m_item_name
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
item_name
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
},
s
.
str
()));
}
...
...
@@ -1012,8 +1021,8 @@ condition operator>=(const key &key, const T &v)
s
<<
" >= "
<<
v
;
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_
tag
,
[
tag
=
key
.
m_item_tag
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
},
key
.
m_item_
name
,
[
item_name
=
key
.
m_item_name
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
item_name
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
},
s
.
str
()));
}
...
...
@@ -1027,8 +1036,8 @@ condition operator<(const key &key, const T &v)
s
<<
" < "
<<
v
;
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_
tag
,
[
tag
=
key
.
m_item_tag
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
},
key
.
m_item_
name
,
[
item_name
=
key
.
m_item_name
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
item_name
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
},
s
.
str
()));
}
...
...
@@ -1042,8 +1051,8 @@ condition operator<=(const key &key, const T &v)
s
<<
" <= "
<<
v
;
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_
tag
,
[
tag
=
key
.
m_item_tag
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
},
key
.
m_item_
name
,
[
item_name
=
key
.
m_item_name
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
item_name
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
},
s
.
str
()));
}
...
...
@@ -1052,7 +1061,7 @@ condition operator<=(const key &key, const T &v)
*/
inline
condition
operator
==
(
const
key
&
key
,
const
std
::
regex
&
rx
)
{
return
condition
(
new
detail
::
key_matches_condition_impl
(
key
.
m_item_
tag
,
rx
));
return
condition
(
new
detail
::
key_matches_condition_impl
(
key
.
m_item_
name
,
rx
));
}
/**
...
...
@@ -1060,7 +1069,7 @@ inline condition operator==(const key &key, const std::regex &rx)
*/
inline
condition
operator
==
(
const
key
&
key
,
const
empty_type
&
)
{
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_
tag
));
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_
name
));
}
/**
...
...
@@ -1068,20 +1077,20 @@ inline condition operator==(const key &key, const empty_type &)
*/
inline
condition
operator
!=
(
const
key
&
key
,
const
empty_type
&
)
{
return
condition
(
new
detail
::
key_is_not_empty_condition_impl
(
key
.
m_item_
tag
));
return
condition
(
new
detail
::
key_is_not_empty_condition_impl
(
key
.
m_item_
name
));
}
/**
* @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
>
condition
operator
==
(
const
key
&
key
,
const
std
::
optional
<
T
>
&
v
)
{
if
(
v
.
has_value
())
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_
tag
,
*
v
}));
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_
name
,
*
v
}));
else
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_
tag
));
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_
name
));
}
/**
...
...
@@ -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++/datablock.hpp
View file @
30a2ebdb
...
...
@@ -169,7 +169,16 @@ class datablock : public std::list<category>
/**
* @brief Get the preferred order of the categories when writing them
*/
std
::
vector
<
std
::
string
>
get_tag_order
()
const
;
[[
deprecated
(
"use get_item_order instead"
)]]
std
::
vector
<
std
::
string
>
get_tag_order
()
const
{
return
get_item_order
();
}
/**
* @brief Get the preferred order of the categories when writing them
*/
std
::
vector
<
std
::
string
>
get_item_order
()
const
;
/**
* @brief Write out the contents to @a os
...
...
@@ -177,9 +186,9 @@ class datablock : public std::list<category>
void
write
(
std
::
ostream
&
os
)
const
;
/**
* @brief Write out the contents to @a os using the order defined in @a
tag
_order
* @brief Write out the contents to @a os using the order defined in @a
item_name
_order
*/
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
tag
_order
);
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
item_name
_order
);
/**
* @brief Friend operator<< to write datablock @a db to std::ostream @a os
...
...
include/cif++/item.hpp
View file @
30a2ebdb
...
...
@@ -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 @
30a2ebdb
...
...
@@ -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 @
30a2ebdb
...
...
@@ -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 @
30a2ebdb
...
...
@@ -143,9 +143,9 @@ class sac_parser
enum
class
CIFToken
{
U
nknown
,
U
NKNOWN
,
E
of
,
E
ND_OF_FILE
,
DATA
,
LOOP
,
...
...
@@ -153,24 +153,24 @@ class sac_parser
SAVE_
,
SAVE_NAME
,
STOP
,
Tag
,
V
alue
ITEM_NAME
,
V
ALUE
};
static
constexpr
const
char
*
get_token_name
(
CIFToken
token
)
{
switch
(
token
)
{
case
CIFToken
:
:
U
nknown
:
return
"Unknown"
;
case
CIFToken
:
:
E
of
:
return
"Eof"
;
case
CIFToken
:
:
U
NKNOWN
:
return
"Unknown"
;
case
CIFToken
:
:
E
ND_OF_FILE
:
return
"Eof"
;
case
CIFToken
:
:
DATA
:
return
"DATA"
;
case
CIFToken
:
:
LOOP
:
return
"LOOP"
;
case
CIFToken
:
:
GLOBAL
:
return
"GLOBAL"
;
case
CIFToken
:
:
SAVE_
:
return
"SAVE"
;
case
CIFToken
:
:
SAVE_NAME
:
return
"SAVE+name"
;
case
CIFToken
:
:
STOP
:
return
"STOP"
;
case
CIFToken
:
:
Tag
:
return
"Tag"
;
case
CIFToken
:
:
V
alue
:
return
"Value"
;
case
CIFToken
:
:
ITEM_NAME
:
return
"Tag"
;
case
CIFToken
:
:
V
ALUE
:
return
"Value"
;
default:
return
"Invalid token parameter"
;
}
}
...
...
@@ -267,9 +267,9 @@ class sac_parser
QuotedString
,
QuotedStringQuote
,
UnquotedString
,
Tag
,
Text
Field
,
Text
Field
NL
,
ItemName
,
Text
Item
,
Text
Item
NL
,
Reserved
,
Value
};
...
...
include/cif++/pdb.hpp
View file @
30a2ebdb
...
...
@@ -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 @
30a2ebdb
...
...
@@ -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++/text.hpp
View file @
30a2ebdb
...
...
@@ -317,7 +317,7 @@ inline char tolower(int ch)
// --------------------------------------------------------------------
/** \brief return a tuple consisting of the category and item name for @a
tag
/** \brief return a tuple consisting of the category and item name for @a
item_name
*
* The category name is stripped of its leading underscore character.
*
...
...
@@ -325,7 +325,19 @@ inline char tolower(int ch)
* cif 1.0 formatted data.
*/
std
::
tuple
<
std
::
string
,
std
::
string
>
split_tag_name
(
std
::
string_view
tag
);
[[
deprecated
(
"use split_item_name instead"
)]]
std
::
tuple
<
std
::
string
,
std
::
string
>
split_tag_name
(
std
::
string_view
item_name
);
/** \brief return a tuple consisting of the category and item name for @a item_name
*
* The category name is stripped of its leading underscore character.
*
* If no dot character was found, the category name is empty. That's for
* cif 1.0 formatted data.
*/
std
::
tuple
<
std
::
string
,
std
::
string
>
split_item_name
(
std
::
string_view
item_name
);
// --------------------------------------------------------------------
...
...
include/cif++/validate.hpp
View file @
30a2ebdb
...
...
@@ -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
;
/**
...
...
@@ -177,7 +276,7 @@ struct item_alias
*/
struct
item_validator
{
std
::
string
m_
tag
;
///< The item name
std
::
string
m_
item_name
;
///< The item name
bool
m_mandatory
;
///< Flag indicating this item is mandatory
const
type_validator
*
m_type
;
///< The type for this item
cif
::
iset
m_enums
;
///< If filled, the set of allowed values
...
...
@@ -188,18 +287,21 @@ struct item_validator
/// @brief Compare based on the name
bool
operator
<
(
const
item_validator
&
rhs
)
const
{
return
icompare
(
m_
tag
,
rhs
.
m_tag
)
<
0
;
return
icompare
(
m_
item_name
,
rhs
.
m_item_name
)
<
0
;
}
/// @brief Compare based on the name
bool
operator
==
(
const
item_validator
&
rhs
)
const
{
return
iequals
(
m_
tag
,
rhs
.
m_tag
);
return
iequals
(
m_
item_name
,
rhs
.
m_item_name
);
}
/// @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
;
};
/**
...
...
@@ -213,7 +315,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
...
...
@@ -225,11 +327,11 @@ struct category_validator
/// @brief Add item_validator @a v to the list of item validators
void
add_item_validator
(
item_validator
&&
v
);
/// @brief Return the item_validator for item @a
tag
, may return nullptr
const
item_validator
*
get_validator_for_item
(
std
::
string_view
tag
)
const
;
/// @brief Return the item_validator for item @a
item_name
, may return nullptr
const
item_validator
*
get_validator_for_item
(
std
::
string_view
item_name
)
const
;
/// @brief Return the item_validator for an item that has as alias name @a
tag
, may return nullptr
const
item_validator
*
get_validator_for_aliased_item
(
std
::
string_view
tag
)
const
;
/// @brief Return the item_validator for an item that has as alias name @a
item_name
, may return nullptr
const
item_validator
*
get_validator_for_aliased_item
(
std
::
string_view
item_name
)
const
;
};
/**
...
...
@@ -308,7 +410,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 @
30a2ebdb
...
...
@@ -33,7 +33,7 @@
#include <stack>
// TODO: Find out what the rules are exactly for linked items, the current implementation
// is inconsistent. It all depends whether a link is satified if a
field
taking part in the
// is inconsistent. It all depends whether a link is satified if a
item
taking part in the
// set of linked items is null at one side and not null in the other.
namespace
cif
...
...
@@ -52,7 +52,7 @@ class row_comparator
for
(
auto
&
k
:
cv
->
m_keys
)
{
uint16_t
ix
=
cat
.
add_
column
(
k
);
uint16_t
ix
=
cat
.
add_
item
(
k
);
auto
iv
=
cv
->
get_validator_for_item
(
k
);
if
(
iv
==
nullptr
)
...
...
@@ -300,7 +300,7 @@ class category_index
return
h
;
}
// Fix m_next
field
s for rows in order of this index
// Fix m_next
item
s for rows in order of this index
entry
*
reorder
(
entry
*
e
)
{
auto
result
=
e
;
...
...
@@ -356,9 +356,9 @@ row *category_index::find_by_value(const category &cat, row_initializer k) const
// sort the values in k first
row_initializer
k2
;
for
(
auto
&
f
:
cat
.
key_
field
_indices
())
for
(
auto
&
f
:
cat
.
key_
item
_indices
())
{
auto
fld
=
cat
.
get_
column
_name
(
f
);
auto
fld
=
cat
.
get_
item
_name
(
f
);
auto
ki
=
find_if
(
k
.
begin
(),
k
.
end
(),
[
&
fld
](
auto
&
i
)
{
return
i
.
name
()
==
fld
;
});
...
...
@@ -404,7 +404,7 @@ category_index::entry *category_index::insert(category &cat, entry *h, row *v)
row_handle
rh
(
cat
,
*
v
);
std
::
ostringstream
os
;
for
(
auto
col
:
cat
.
key_
field
s
())
for
(
auto
col
:
cat
.
key_
item
s
())
{
if
(
rh
[
col
])
os
<<
col
<<
": "
<<
std
::
quoted
(
rh
[
col
].
text
())
<<
"; "
;
...
...
@@ -508,7 +508,7 @@ category::category(std::string_view name)
category
::
category
(
const
category
&
rhs
)
:
m_name
(
rhs
.
m_name
)
,
m_
columns
(
rhs
.
m_column
s
)
,
m_
items
(
rhs
.
m_item
s
)
,
m_cascade
(
rhs
.
m_cascade
)
{
for
(
auto
r
=
rhs
.
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
...
...
@@ -523,7 +523,7 @@ category::category(const category &rhs)
category
::
category
(
category
&&
rhs
)
:
m_name
(
std
::
move
(
rhs
.
m_name
))
,
m_
columns
(
std
::
move
(
rhs
.
m_column
s
))
,
m_
items
(
std
::
move
(
rhs
.
m_item
s
))
,
m_validator
(
rhs
.
m_validator
)
,
m_cat_validator
(
rhs
.
m_cat_validator
)
,
m_parent_links
(
std
::
move
(
rhs
.
m_parent_links
))
...
...
@@ -546,7 +546,7 @@ category &category::operator=(const category &rhs)
clear
();
m_name
=
rhs
.
m_name
;
m_
columns
=
rhs
.
m_column
s
;
m_
items
=
rhs
.
m_item
s
;
m_cascade
=
rhs
.
m_cascade
;
m_validator
=
nullptr
;
...
...
@@ -573,7 +573,7 @@ category &category::operator=(category &&rhs)
if
(
this
!=
&
rhs
)
{
m_name
=
std
::
move
(
rhs
.
m_name
);
m_
columns
=
std
::
move
(
rhs
.
m_column
s
);
m_
items
=
std
::
move
(
rhs
.
m_item
s
);
m_cascade
=
rhs
.
m_cascade
;
m_validator
=
rhs
.
m_validator
;
m_cat_validator
=
rhs
.
m_cat_validator
;
...
...
@@ -595,11 +595,11 @@ category::~category()
// --------------------------------------------------------------------
void
category
::
remove_
column
(
std
::
string_view
column
_name
)
void
category
::
remove_
item
(
std
::
string_view
item
_name
)
{
for
(
size_t
ix
=
0
;
ix
<
m_
column
s
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
m_
item
s
.
size
();
++
ix
)
{
if
(
not
iequals
(
column_name
,
m_column
s
[
ix
].
m_name
))
if
(
not
iequals
(
item_name
,
m_item
s
[
ix
].
m_name
))
continue
;
for
(
row
*
r
=
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
...
...
@@ -608,62 +608,62 @@ void category::remove_column(std::string_view column_name)
r
->
erase
(
r
->
begin
()
+
ix
);
}
m_
columns
.
erase
(
m_column
s
.
begin
()
+
ix
);
m_
items
.
erase
(
m_item
s
.
begin
()
+
ix
);
break
;
}
}
void
category
::
rename_
column
(
std
::
string_view
from_name
,
std
::
string_view
to_name
)
void
category
::
rename_
item
(
std
::
string_view
from_name
,
std
::
string_view
to_name
)
{
for
(
size_t
ix
=
0
;
ix
<
m_
column
s
.
size
();
++
ix
)
for
(
size_t
ix
=
0
;
ix
<
m_
item
s
.
size
();
++
ix
)
{
if
(
not
iequals
(
from_name
,
m_
column
s
[
ix
].
m_name
))
if
(
not
iequals
(
from_name
,
m_
item
s
[
ix
].
m_name
))
continue
;
m_
column
s
[
ix
].
m_name
=
to_name
;
m_
column
s
[
ix
].
m_validator
=
m_cat_validator
?
m_cat_validator
->
get_validator_for_item
(
to_name
)
:
nullptr
;
m_
item
s
[
ix
].
m_name
=
to_name
;
m_
item
s
[
ix
].
m_validator
=
m_cat_validator
?
m_cat_validator
->
get_validator_for_item
(
to_name
)
:
nullptr
;
break
;
}
}
iset
category
::
get_
column
s
()
const
iset
category
::
get_
item
s
()
const
{
iset
result
;
for
(
auto
&
col
:
m_
column
s
)
for
(
auto
&
col
:
m_
item
s
)
result
.
insert
(
col
.
m_name
);
return
result
;
}
iset
category
::
key_
field
s
()
const
iset
category
::
key_
item
s
()
const
{
if
(
m_validator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
m_cat_validator
==
nullptr
)
m_validator
->
report_error
(
"undefined Category"
,
true
);
m_validator
->
report_error
(
validation_error
::
undefined_category
);
iset
result
;
for
(
auto
&
iv
:
m_cat_validator
->
m_item_validators
)
result
.
insert
(
iv
.
m_
tag
);
result
.
insert
(
iv
.
m_
item_name
);
return
result
;
}
std
::
set
<
uint16_t
>
category
::
key_
field
_indices
()
const
std
::
set
<
uint16_t
>
category
::
key_
item
_indices
()
const
{
if
(
m_validator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
m_cat_validator
==
nullptr
)
m_validator
->
report_error
(
"undefined Category"
,
true
);
m_validator
->
report_error
(
validation_error
::
undefined_category
);
std
::
set
<
uint16_t
>
result
;
for
(
auto
&
k
:
m_cat_validator
->
m_keys
)
result
.
insert
(
get_
column
_ix
(
k
));
result
.
insert
(
get_
item
_ix
(
k
));
return
result
;
}
...
...
@@ -693,8 +693,8 @@ void category::set_validator(const validator *v, datablock &db)
std
::
vector
<
uint16_t
>
kix
;
for
(
auto
k
:
m_cat_validator
->
m_keys
)
{
kix
.
push_back
(
get_
column
_ix
(
k
));
if
(
kix
.
back
()
>=
m_
column
s
.
size
())
kix
.
push_back
(
get_
item
_ix
(
k
));
if
(
kix
.
back
()
>=
m_
item
s
.
size
())
missing
.
insert
(
k
);
}
}
...
...
@@ -704,7 +704,7 @@ void category::set_validator(const validator *v, datablock &db)
else
{
std
::
ostringstream
msg
;
msg
<<
"Cannot construct index since the key
field
"
<<
(
missing
.
size
()
>
1
?
"s"
:
""
)
<<
" "
msg
<<
"Cannot construct index since the key
item
"
<<
(
missing
.
size
()
>
1
?
"s"
:
""
)
<<
" "
<<
cif
::
join
(
missing
,
", "
)
<<
" in "
<<
m_name
<<
" "
<<
(
missing
.
size
()
==
1
?
"is"
:
"are"
)
<<
" missing
\n
"
;
throw
missing_key_error
(
msg
.
str
(),
*
missing
.
begin
());
}
...
...
@@ -713,8 +713,8 @@ void category::set_validator(const validator *v, datablock &db)
else
m_cat_validator
=
nullptr
;
for
(
auto
&&
[
column
,
cv
]
:
m_column
s
)
cv
=
m_cat_validator
?
m_cat_validator
->
get_validator_for_item
(
column
)
:
nullptr
;
for
(
auto
&&
[
item
,
cv
]
:
m_item
s
)
cv
=
m_cat_validator
?
m_cat_validator
->
get_validator_for_item
(
item
)
:
nullptr
;
update_links
(
db
);
}
...
...
@@ -760,31 +760,31 @@ bool category::is_valid() const
if
(
m_cat_validator
==
nullptr
)
{
m_validator
->
report_error
(
"undefined category "
+
m_name
,
false
);
m_validator
->
report_error
(
validation_error
::
undefined_category
,
m_name
,
{}
,
false
);
return
false
;
}
auto
mandatory
=
m_cat_validator
->
m_mandatory_
field
s
;
auto
mandatory
=
m_cat_validator
->
m_mandatory_
item
s
;
for
(
auto
&
col
:
m_
column
s
)
for
(
auto
&
col
:
m_
item
s
)
{
auto
iv
=
m_cat_validator
->
get_validator_for_item
(
col
.
m_name
);
if
(
iv
==
nullptr
)
{
m_validator
->
report_error
(
"Field "
+
col
.
m_name
+
" is not valid in category "
+
m_name
,
false
);
m_validator
->
report_error
(
validation_error
::
unknown_item
,
col
.
m_name
,
m_name
,
false
);
result
=
false
;
}
// col.m_validator = iv;
if
(
col
.
m_validator
!=
iv
)
m_validator
->
report_error
(
"Column validator is not specified correctly"
,
true
);
m_validator
->
report_error
(
validation_error
::
incorrect_item_validator
,
true
);
mandatory
.
erase
(
col
.
m_name
);
}
if
(
not
mandatory
.
empty
())
{
m_validator
->
report_error
(
"In category "
+
m_name
+
" the following mandatory fields are missing: "
+
join
(
mandatory
,
", "
),
false
);
m_validator
->
report_error
(
validation_error
::
missing_mandatory_items
,
m_name
,
join
(
mandatory
,
", "
),
false
);
result
=
false
;
}
...
...
@@ -794,44 +794,44 @@ bool category::is_valid() const
for
(
auto
k
:
m_cat_validator
->
m_keys
)
{
if
(
get_
column_ix
(
k
)
>=
m_column
s
.
size
())
if
(
get_
item_ix
(
k
)
>=
m_item
s
.
size
())
missing
.
insert
(
k
);
}
m_validator
->
report_error
(
"In category "
+
m_name
+
" the index is missing, likely due to missing key fields: "
+
join
(
missing
,
", "
),
false
);
m_validator
->
report_error
(
validation_error
::
missing_key_items
,
m_name
,
join
(
missing
,
", "
),
false
);
result
=
false
;
}
#if not defined(NDEBUG)
// check index?
if
(
m_index
)
{
if
(
m_index
->
size
()
!=
size
())
m_validator
->
report_error
(
"size of index is not equal to size of category "
+
m_name
,
true
);
// m_index->validate();
for
(
auto
r
:
*
this
)
{
auto
p
=
r
.
get_row
();
if
(
m_index
->
find
(
*
this
,
p
)
!=
p
)
m_validator
->
report_error
(
"Key not found in index for category "
+
m_name
,
true
);
}
}
#endif
//
#if not defined(NDEBUG)
//
//
check index?
//
if (m_index)
//
{
//
if (m_index->size() != size())
//
m_validator->report_error("size of index is not equal to size of category " + m_name, true);
//
// m_index->validate();
//
for (auto r : *this)
//
{
//
auto p = r.get_row();
//
if (m_index->find(*this, p) != p)
//
m_validator->report_error("Key not found in index for category " + m_name, true);
//
}
//
}
//
#endif
// validate all values
mandatory
=
m_cat_validator
->
m_mandatory_
field
s
;
mandatory
=
m_cat_validator
->
m_mandatory_
item
s
;
for
(
auto
ri
=
m_head
;
ri
!=
nullptr
;
ri
=
ri
->
m_next
)
{
for
(
uint16_t
cix
=
0
;
cix
<
m_
column
s
.
size
();
++
cix
)
for
(
uint16_t
cix
=
0
;
cix
<
m_
item
s
.
size
();
++
cix
)
{
bool
seen
=
false
;
auto
iv
=
m_
column
s
[
cix
].
m_validator
;
auto
iv
=
m_
item
s
[
cix
].
m_validator
;
if
(
iv
==
nullptr
)
{
m_validator
->
report_error
(
"invalid field "
+
m_columns
[
cix
].
m_name
+
" for category "
+
m_name
,
false
);
m_validator
->
report_error
(
validation_error
::
unknown_item
,
m_name
,
m_items
[
cix
].
m_name
,
false
);
result
=
false
;
continue
;
}
...
...
@@ -840,14 +840,13 @@ bool category::is_valid() const
if
(
vi
!=
nullptr
)
{
seen
=
true
;
try
{
(
*
iv
)(
vi
->
text
()
);
}
catch
(
const
std
::
exception
&
e
)
std
::
error_code
ec
;
iv
->
validate_value
(
vi
->
text
(),
ec
);
if
(
ec
!=
std
::
errc
()
)
{
result
=
false
;
m_validator
->
report_error
(
"Error validating "
+
m_columns
[
cix
].
m_name
+
": "
+
e
.
what
(),
false
);
m_validator
->
report_error
(
ec
,
m_name
,
m_items
[
cix
].
m_name
,
false
);
continue
;
}
}
...
...
@@ -857,7 +856,7 @@ bool category::is_valid() const
if
(
iv
!=
nullptr
and
iv
->
m_mandatory
)
{
m_validator
->
report_error
(
"missing mandatory field "
+
m_columns
[
cix
].
m_name
+
" for category "
+
m_name
,
false
);
m_validator
->
report_error
(
validation_error
::
missing_mandatory_items
,
m_name
,
m_items
[
cix
].
m_name
,
false
);
result
=
false
;
}
}
...
...
@@ -989,10 +988,10 @@ condition category::get_children_condition(row_handle rh, const category &childC
condition
result
;
iset
mandatoryChild
Field
s
;
iset
mandatoryChild
Item
s
;
auto
childCatValidator
=
m_validator
->
get_validator_for_category
(
childCat
.
name
());
if
(
childCatValidator
!=
nullptr
)
mandatoryChild
Fields
=
childCatValidator
->
m_mandatory_field
s
;
mandatoryChild
Items
=
childCatValidator
->
m_mandatory_item
s
;
auto
links
=
m_validator
->
get_links_for_parent
(
m_name
);
links
.
erase
(
remove_if
(
links
.
begin
(),
links
.
end
(),
[
n
=
childCat
.
m_name
](
auto
&
l
)
...
...
@@ -1014,7 +1013,7 @@ condition category::get_children_condition(row_handle rh, const category &childC
if
(
parentValue
.
empty
())
cond
=
std
::
move
(
cond
)
and
key
(
childKey
)
==
null
;
else
if
(
link
->
m_parent_keys
.
size
()
>
1
and
not
mandatoryChild
Field
s
.
contains
(
childKey
))
else
if
(
link
->
m_parent_keys
.
size
()
>
1
and
not
mandatoryChild
Item
s
.
contains
(
childKey
))
cond
=
std
::
move
(
cond
)
and
(
key
(
childKey
)
==
parentValue
.
text
()
or
key
(
childKey
)
==
null
);
else
cond
=
std
::
move
(
cond
)
and
key
(
childKey
)
==
parentValue
.
text
();
...
...
@@ -1281,17 +1280,17 @@ std::string category::get_unique_id(std::function<std::string(int)> generator)
std
::
string
result
=
generator
(
static_cast
<
int
>
(
m_last_unique_num
++
));
std
::
string
id_
tag
=
"id"
;
std
::
string
id_
name
=
"id"
;
if
(
m_cat_validator
!=
nullptr
and
m_cat_validator
->
m_keys
.
size
()
==
1
)
{
id_
tag
=
m_cat_validator
->
m_keys
.
front
();
id_
name
=
m_cat_validator
->
m_keys
.
front
();
if
(
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
m_index
=
new
category_index
(
*
this
);
for
(;;)
{
if
(
m_index
->
find_by_value
(
*
this
,
{
{
id_
tag
,
result
}
})
==
nullptr
)
if
(
m_index
->
find_by_value
(
*
this
,
{
{
id_
name
,
result
}
})
==
nullptr
)
break
;
result
=
generator
(
static_cast
<
int
>
(
m_last_unique_num
++
));
}
...
...
@@ -1300,7 +1299,7 @@ std::string category::get_unique_id(std::function<std::string(int)> generator)
{
for
(;;)
{
if
(
not
contains
(
key
(
id_
tag
)
==
result
))
if
(
not
contains
(
key
(
id_
name
)
==
result
))
break
;
result
=
generator
(
static_cast
<
int
>
(
m_last_unique_num
++
));
...
...
@@ -1310,17 +1309,17 @@ std::string category::get_unique_id(std::function<std::string(int)> generator)
return
result
;
}
std
::
string
category
::
get_unique_value
(
std
::
string_view
tag
)
std
::
string
category
::
get_unique_value
(
std
::
string_view
item_name
)
{
std
::
string
result
;
if
(
m_validator
and
m_cat_validator
)
{
auto
iv
=
m_cat_validator
->
get_validator_for_item
(
tag
);
auto
iv
=
m_cat_validator
->
get_validator_for_item
(
item_name
);
if
(
iv
and
iv
->
m_type
and
iv
->
m_type
->
m_primitive_type
==
DDL_PrimitiveType
::
Numb
)
{
uint64_t
v
=
find_max
<
uint64_t
>
(
tag
);
uint64_t
v
=
find_max
<
uint64_t
>
(
item_name
);
result
=
std
::
to_string
(
v
+
1
);
}
}
...
...
@@ -1332,7 +1331,7 @@ std::string category::get_unique_value(std::string_view tag)
{
// result = m_name + "-" + std::to_string(ix);
result
=
cif_id_for_number
(
ix
);
if
(
not
contains
(
key
(
tag
)
==
result
))
if
(
not
contains
(
key
(
item_name
)
==
result
))
break
;
}
}
...
...
@@ -1340,28 +1339,28 @@ std::string category::get_unique_value(std::string_view tag)
return
result
;
}
void
category
::
update_value
(
const
std
::
vector
<
row_handle
>
&
rows
,
std
::
string_view
tag
,
std
::
string_view
value
)
void
category
::
update_value
(
const
std
::
vector
<
row_handle
>
&
rows
,
std
::
string_view
item_name
,
std
::
string_view
value
)
{
using
namespace
std
::
literals
;
if
(
rows
.
empty
())
return
;
auto
colIx
=
get_
column_ix
(
tag
);
if
(
colIx
>=
m_
column
s
.
size
())
throw
std
::
runtime_error
(
"Invalid
column
"
+
std
::
string
{
value
}
+
" for "
+
m_name
);
auto
colIx
=
get_
item_ix
(
item_name
);
if
(
colIx
>=
m_
item
s
.
size
())
throw
std
::
runtime_error
(
"Invalid
item
"
+
std
::
string
{
value
}
+
" for "
+
m_name
);
auto
&
col
=
m_
column
s
[
colIx
];
auto
&
col
=
m_
item
s
[
colIx
];
// check the value
if
(
col
.
m_validator
)
(
*
col
.
m_validator
)(
value
);
// first some sanity checks, what was the old value and is it the same for all rows?
std
::
string
oldValue
{
rows
.
front
()[
tag
].
text
()
};
std
::
string
oldValue
{
rows
.
front
()[
item_name
].
text
()
};
for
(
auto
row
:
rows
)
{
if
(
oldValue
!=
row
[
tag
].
text
())
if
(
oldValue
!=
row
[
item_name
].
text
())
throw
std
::
runtime_error
(
"Inconsistent old values in update_value"
);
}
...
...
@@ -1377,20 +1376,20 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
{
for
(
auto
&&
[
childCat
,
linked
]
:
m_child_links
)
{
if
(
std
::
find
(
linked
->
m_parent_keys
.
begin
(),
linked
->
m_parent_keys
.
end
(),
tag
)
==
linked
->
m_parent_keys
.
end
())
if
(
std
::
find
(
linked
->
m_parent_keys
.
begin
(),
linked
->
m_parent_keys
.
end
(),
item_name
)
==
linked
->
m_parent_keys
.
end
())
continue
;
condition
cond
;
std
::
string
child
Tag
;
std
::
string
child
ItemName
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
m_parent_keys
.
size
();
++
ix
)
{
std
::
string
pk
=
linked
->
m_parent_keys
[
ix
];
std
::
string
ck
=
linked
->
m_child_keys
[
ix
];
if
(
pk
==
tag
)
if
(
pk
==
item_name
)
{
child
Tag
=
ck
;
child
ItemName
=
ck
;
cond
=
std
::
move
(
cond
)
&&
key
(
ck
)
==
oldValue
;
}
else
...
...
@@ -1437,7 +1436,7 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
std
::
string
pk
=
linked
->
m_parent_keys
[
ix
];
std
::
string
ck
=
linked
->
m_child_keys
[
ix
];
if
(
pk
==
tag
)
if
(
pk
==
item_name
)
check
=
std
::
move
(
check
)
&&
key
(
ck
)
==
value
;
else
check
=
std
::
move
(
check
)
&&
key
(
ck
)
==
parent
[
pk
].
text
();
...
...
@@ -1459,27 +1458,27 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
// cannot update this...
if
(
cif
::
VERBOSE
>
0
)
std
::
cerr
<<
"Cannot update child "
<<
childCat
->
m_name
<<
"."
<<
child
Tag
<<
" with value "
<<
value
<<
'\n'
;
std
::
cerr
<<
"Cannot update child "
<<
childCat
->
m_name
<<
"."
<<
child
ItemName
<<
" with value "
<<
value
<<
'\n'
;
}
// finally, update the children
if
(
not
process
.
empty
())
childCat
->
update_value
(
process
,
child
Tag
,
value
);
childCat
->
update_value
(
process
,
child
ItemName
,
value
);
}
}
}
void
category
::
update_value
(
row
*
row
,
uint16_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
)
void
category
::
update_value
(
row
*
row
,
uint16_t
item
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
)
{
// make sure we have an index, if possible
if
((
updateLinked
or
validate
)
and
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
m_index
=
new
category_index
(
*
this
);
auto
&
col
=
m_
columns
[
column
];
auto
&
col
=
m_
items
[
item
];
std
::
string_view
oldValue
;
auto
ival
=
row
->
get
(
column
);
auto
ival
=
row
->
get
(
item
);
if
(
ival
!=
nullptr
)
oldValue
=
ival
->
text
();
...
...
@@ -1492,12 +1491,12 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
if
(
col
.
m_validator
and
validate
)
col
.
m_validator
->
operator
()(
value
);
// If the
field
is part of the Key for this category, remove it from the index
// If the
item
is part of the Key for this category, remove it from the index
// before updating
bool
reinsert
=
false
;
if
(
updateLinked
and
// an update of an Item's value
m_index
!=
nullptr
and
key_
field_indices
().
count
(
column
))
m_index
!=
nullptr
and
key_
item_indices
().
count
(
item
))
{
reinsert
=
m_index
->
find
(
*
this
,
row
);
if
(
reinsert
)
...
...
@@ -1506,10 +1505,10 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
// first remove old value with cix
if
(
ival
!=
nullptr
)
row
->
remove
(
column
);
row
->
remove
(
item
);
if
(
not
value
.
empty
())
row
->
append
(
column
,
{
value
});
row
->
append
(
item
,
{
value
});
if
(
reinsert
and
m_index
!=
nullptr
)
m_index
->
insert
(
*
this
,
row
);
...
...
@@ -1522,22 +1521,22 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
for
(
auto
&&
[
childCat
,
linked
]
:
m_child_links
)
{
if
(
std
::
find
(
linked
->
m_parent_keys
.
begin
(),
linked
->
m_parent_keys
.
end
(),
iv
->
m_
tag
)
==
linked
->
m_parent_keys
.
end
())
if
(
std
::
find
(
linked
->
m_parent_keys
.
begin
(),
linked
->
m_parent_keys
.
end
(),
iv
->
m_
item_name
)
==
linked
->
m_parent_keys
.
end
())
continue
;
condition
cond
;
std
::
string
child
Tag
;
std
::
string
child
ItemName
;
for
(
size_t
ix
=
0
;
ix
<
linked
->
m_parent_keys
.
size
();
++
ix
)
{
std
::
string
pk
=
linked
->
m_parent_keys
[
ix
];
std
::
string
ck
=
linked
->
m_child_keys
[
ix
];
// TODO: add code to *NOT* test mandatory
field
s for Empty
// TODO: add code to *NOT* test mandatory
item
s for Empty
if
(
pk
==
iv
->
m_
tag
)
if
(
pk
==
iv
->
m_
item_name
)
{
child
Tag
=
ck
;
child
ItemName
=
ck
;
cond
=
std
::
move
(
cond
)
and
key
(
ck
)
==
oldStrValue
;
}
else
...
...
@@ -1570,7 +1569,7 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
std
::
string
pk
=
linked
->
m_parent_keys
[
ix
];
std
::
string
ck
=
linked
->
m_child_keys
[
ix
];
if
(
pk
==
iv
->
m_
tag
)
if
(
pk
==
iv
->
m_
item_name
)
cond_n
=
std
::
move
(
cond_n
)
and
key
(
ck
)
==
value
;
else
{
...
...
@@ -1592,7 +1591,7 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
}
for
(
auto
cr
:
rows
)
cr
.
assign
(
child
Tag
,
value
,
false
);
cr
.
assign
(
child
ItemName
,
value
,
false
);
}
}
}
...
...
@@ -1640,7 +1639,7 @@ row_handle category::create_copy(row_handle r)
{
auto
i
=
r
.
m_row
->
get
(
ix
);
if
(
i
!=
nullptr
)
items
.
emplace_back
(
m_
column
s
[
ix
].
m_name
,
i
->
text
());
items
.
emplace_back
(
m_
item
s
[
ix
].
m_name
,
i
->
text
());
}
if
(
m_cat_validator
and
m_cat_validator
->
m_keys
.
size
()
==
1
)
...
...
@@ -1683,12 +1682,12 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
try
{
// First, make sure all mandatory
field
s are supplied
// First, make sure all mandatory
item
s are supplied
if
(
m_cat_validator
!=
nullptr
)
{
for
(
uint16_t
ix
=
0
;
ix
<
static_cast
<
uint16_t
>
(
m_
column
s
.
size
());
++
ix
)
for
(
uint16_t
ix
=
0
;
ix
<
static_cast
<
uint16_t
>
(
m_
item
s
.
size
());
++
ix
)
{
const
auto
&
[
column
,
iv
]
=
m_column
s
[
ix
];
const
auto
&
[
item
,
iv
]
=
m_item
s
[
ix
];
if
(
iv
==
nullptr
)
continue
;
...
...
@@ -1703,7 +1702,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
}
if
(
not
seen
and
iv
->
m_mandatory
)
throw
std
::
runtime_error
(
"missing mandatory
field "
+
column
+
" for category "
+
m_name
);
throw
std
::
runtime_error
(
"missing mandatory
item "
+
item
+
" for category "
+
m_name
);
}
}
...
...
@@ -1742,7 +1741,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
// #endif
}
void
category
::
swap_item
(
uint16_t
column
_ix
,
row_handle
&
a
,
row_handle
&
b
)
void
category
::
swap_item
(
uint16_t
item
_ix
,
row_handle
&
a
,
row_handle
&
b
)
{
assert
(
this
==
a
.
m_category
);
assert
(
this
==
b
.
m_category
);
...
...
@@ -1750,7 +1749,7 @@ void category::swap_item(uint16_t column_ix, row_handle &a, row_handle &b)
auto
&
ra
=
*
a
.
m_row
;
auto
&
rb
=
*
b
.
m_row
;
std
::
swap
(
ra
.
at
(
column_ix
),
rb
.
at
(
column
_ix
));
std
::
swap
(
ra
.
at
(
item_ix
),
rb
.
at
(
item
_ix
));
}
void
category
::
sort
(
std
::
function
<
int
(
row_handle
,
row_handle
)
>
f
)
...
...
@@ -1790,7 +1789,7 @@ namespace detail
{
size_t
write_value
(
std
::
ostream
&
os
,
std
::
string_view
value
,
size_t
offset
,
size_t
width
,
bool
right_aligned
)
{
if
(
value
.
find
(
'\n'
)
!=
std
::
string
::
npos
or
width
==
0
or
value
.
length
()
>
132
)
// write as text
field
if
(
value
.
find
(
'\n'
)
!=
std
::
string
::
npos
or
width
==
0
or
value
.
length
()
>
132
)
// write as text
item
{
if
(
offset
>
0
)
os
<<
'\n'
;
...
...
@@ -1885,36 +1884,36 @@ namespace detail
}
// namespace detail
std
::
vector
<
std
::
string
>
category
::
get_
tag
_order
()
const
std
::
vector
<
std
::
string
>
category
::
get_
item
_order
()
const
{
std
::
vector
<
std
::
string
>
result
;
for
(
auto
&
c
:
m_
column
s
)
for
(
auto
&
c
:
m_
item
s
)
result
.
push_back
(
"_"
+
m_name
+
"."
+
c
.
m_name
);
return
result
;
}
void
category
::
write
(
std
::
ostream
&
os
)
const
{
std
::
vector
<
uint16_t
>
order
(
m_
column
s
.
size
());
std
::
vector
<
uint16_t
>
order
(
m_
item
s
.
size
());
iota
(
order
.
begin
(),
order
.
end
(),
static_cast
<
uint16_t
>
(
0
));
write
(
os
,
order
,
false
);
}
void
category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
columns
,
bool
addMissingColumn
s
)
void
category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
items
,
bool
addMissingItem
s
)
{
// make sure all
column
s are present
for
(
auto
&
c
:
column
s
)
add_
column
(
c
);
// make sure all
item
s are present
for
(
auto
&
c
:
item
s
)
add_
item
(
c
);
std
::
vector
<
uint16_t
>
order
;
order
.
reserve
(
m_
column
s
.
size
());
order
.
reserve
(
m_
item
s
.
size
());
for
(
auto
&
c
:
column
s
)
order
.
push_back
(
get_
column
_ix
(
c
));
for
(
auto
&
c
:
item
s
)
order
.
push_back
(
get_
item
_ix
(
c
));
if
(
addMissing
Column
s
)
if
(
addMissing
Item
s
)
{
for
(
uint16_t
i
=
0
;
i
<
m_
column
s
.
size
();
++
i
)
for
(
uint16_t
i
=
0
;
i
<
m_
item
s
.
size
();
++
i
)
{
if
(
std
::
find
(
order
.
begin
(),
order
.
end
(),
i
)
==
order
.
end
())
order
.
push_back
(
i
);
...
...
@@ -1924,7 +1923,7 @@ void category::write(std::ostream &os, const std::vector<std::string> &columns,
write
(
os
,
order
,
true
);
}
void
category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
uint16_t
>
&
order
,
bool
includeEmpty
Column
s
)
const
void
category
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
uint16_t
>
&
order
,
bool
includeEmpty
Item
s
)
const
{
if
(
empty
())
return
;
...
...
@@ -1932,13 +1931,13 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
// If the first Row has a next, we need a loop_
bool
needLoop
=
(
m_head
->
m_next
!=
nullptr
);
std
::
vector
<
bool
>
right_aligned
(
m_
column
s
.
size
(),
false
);
std
::
vector
<
bool
>
right_aligned
(
m_
item
s
.
size
(),
false
);
if
(
m_cat_validator
!=
nullptr
)
{
for
(
auto
cix
:
order
)
{
auto
&
col
=
m_
column
s
[
cix
];
auto
&
col
=
m_
item
s
[
cix
];
right_aligned
[
cix
]
=
col
.
m_validator
!=
nullptr
and
col
.
m_validator
->
m_type
!=
nullptr
and
col
.
m_validator
->
m_type
->
m_primitive_type
==
cif
::
DDL_PrimitiveType
::
Numb
;
...
...
@@ -1949,16 +1948,16 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
{
os
<<
"loop_
\n
"
;
std
::
vector
<
size_t
>
columnWidths
(
m_column
s
.
size
());
std
::
vector
<
size_t
>
itemWidths
(
m_item
s
.
size
());
for
(
auto
cix
:
order
)
{
auto
&
col
=
m_
column
s
[
cix
];
auto
&
col
=
m_
item
s
[
cix
];
os
<<
'_'
;
if
(
not
m_name
.
empty
())
os
<<
m_name
<<
'.'
;
os
<<
col
.
m_name
<<
' '
<<
'\n'
;
column
Widths
[
cix
]
=
2
;
item
Widths
[
cix
]
=
2
;
}
for
(
auto
r
=
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
...
...
@@ -1979,8 +1978,8 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
if
(
l
>
132
)
continue
;
if
(
column
Widths
[
ix
]
<
l
+
1
)
column
Widths
[
ix
]
=
l
+
1
;
if
(
item
Widths
[
ix
]
<
l
+
1
)
item
Widths
[
ix
]
=
l
+
1
;
}
}
}
...
...
@@ -1991,7 +1990,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
for
(
uint16_t
cix
:
order
)
{
size_t
w
=
column
Widths
[
cix
];
size_t
w
=
item
Widths
[
cix
];
std
::
string_view
s
;
auto
iv
=
r
->
get
(
cix
);
...
...
@@ -2031,12 +2030,12 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
// first find the indent level
size_t
l
=
0
;
for
(
auto
&
col
:
m_
column
s
)
for
(
auto
&
col
:
m_
item
s
)
{
std
::
string
tag
=
'_'
+
m_name
+
'.'
+
col
.
m_name
;
std
::
string
item_name
=
'_'
+
m_name
+
'.'
+
col
.
m_name
;
if
(
l
<
tag
.
length
())
l
=
tag
.
length
();
if
(
l
<
item_name
.
length
())
l
=
item_name
.
length
();
}
l
+=
3
;
...
...
@@ -2067,7 +2066,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
for
(
uint16_t
cix
:
order
)
{
auto
&
col
=
m_
column
s
[
cix
];
auto
&
col
=
m_
item
s
[
cix
];
os
<<
'_'
;
if
(
not
m_name
.
empty
())
...
...
@@ -2108,10 +2107,10 @@ bool category::operator==(const category &rhs) const
using
namespace
std
::
placeholders
;
// set<std::string>
tagsA(a.fields()), tagsB(b.field
s());
// set<std::string>
item_namesA(a.items()), item_namesB(b.item
s());
//
// if (
tagsA != tag
sB)
// std::cout << "Unequal number of
field
s\n";
// if (
item_namesA != item_name
sB)
// std::cout << "Unequal number of
item
s\n";
const
category_validator
*
catValidator
=
nullptr
;
...
...
@@ -2120,40 +2119,40 @@ bool category::operator==(const category &rhs) const
catValidator
=
validator
->
get_validator_for_category
(
a
.
name
());
typedef
std
::
function
<
int
(
std
::
string_view
,
std
::
string_view
)
>
compType
;
std
::
vector
<
std
::
tuple
<
std
::
string
,
compType
>>
tag
s
;
std
::
vector
<
std
::
tuple
<
std
::
string
,
compType
>>
item_name
s
;
std
::
vector
<
std
::
string
>
keys
;
std
::
vector
<
size_t
>
keyIx
;
if
(
catValidator
==
nullptr
)
{
for
(
auto
&
tag
:
a
.
get_column
s
())
for
(
auto
&
item_name
:
a
.
get_item
s
())
{
tags
.
push_back
(
std
::
make_tuple
(
tag
,
[](
std
::
string_view
va
,
std
::
string_view
vb
)
item_names
.
push_back
(
std
::
make_tuple
(
item_name
,
[](
std
::
string_view
va
,
std
::
string_view
vb
)
{
return
va
.
compare
(
vb
);
}));
keyIx
.
push_back
(
keys
.
size
());
keys
.
push_back
(
tag
);
keys
.
push_back
(
item_name
);
}
}
else
{
keys
=
catValidator
->
m_keys
;
for
(
auto
&
tag
:
a
.
key_field
s
())
for
(
auto
&
item_name
:
a
.
key_item
s
())
{
auto
iv
=
catValidator
->
get_validator_for_item
(
tag
);
auto
iv
=
catValidator
->
get_validator_for_item
(
item_name
);
if
(
iv
==
nullptr
)
throw
std
::
runtime_error
(
"missing item validator"
);
auto
tv
=
iv
->
m_type
;
if
(
tv
==
nullptr
)
throw
std
::
runtime_error
(
"missing type validator"
);
tags
.
push_back
(
std
::
make_tuple
(
tag
,
std
::
bind
(
&
cif
::
type_validator
::
compare
,
tv
,
std
::
placeholders
::
_1
,
std
::
placeholders
::
_2
)));
item_names
.
push_back
(
std
::
make_tuple
(
item_name
,
std
::
bind
(
&
cif
::
type_validator
::
compare
,
tv
,
std
::
placeholders
::
_1
,
std
::
placeholders
::
_2
)));
auto
pred
=
[
tag
](
const
std
::
string
&
s
)
->
bool
auto
pred
=
[
item_name
](
const
std
::
string
&
s
)
->
bool
{
return
cif
::
iequals
(
tag
,
s
)
==
0
;
return
cif
::
iequals
(
item_name
,
s
)
==
0
;
};
if
(
find_if
(
keys
.
begin
(),
keys
.
end
(),
pred
)
==
keys
.
end
())
keyIx
.
push_back
(
tag
s
.
size
()
-
1
);
keyIx
.
push_back
(
item_name
s
.
size
()
-
1
);
}
}
...
...
@@ -2166,12 +2165,12 @@ bool category::operator==(const category &rhs) const
for
(
auto
kix
:
keyIx
)
{
std
::
string
tag
;
std
::
string
item_name
;
compType
compare
;
std
::
tie
(
tag
,
compare
)
=
tag
s
[
kix
];
std
::
tie
(
item_name
,
compare
)
=
item_name
s
[
kix
];
d
=
compare
(
a
[
tag
].
text
(),
b
[
tag
].
text
());
d
=
compare
(
a
[
item_name
].
text
(),
b
[
item_name
].
text
());
if
(
d
!=
0
)
break
;
...
...
@@ -2193,19 +2192,19 @@ bool category::operator==(const category &rhs) const
std
::
vector
<
std
::
string
>
missingA
,
missingB
,
different
;
for
(
auto
&
tt
:
tag
s
)
for
(
auto
&
tt
:
item_name
s
)
{
std
::
string
tag
;
std
::
string
item_name
;
compType
compare
;
std
::
tie
(
tag
,
compare
)
=
tt
;
std
::
tie
(
item_name
,
compare
)
=
tt
;
// make it an option to compare unapplicable to empty or something
auto
ta
=
ra
[
tag
].
text
();
auto
ta
=
ra
[
item_name
].
text
();
if
(
ta
==
"."
or
ta
==
"?"
)
ta
=
""
;
auto
tb
=
rb
[
tag
].
text
();
auto
tb
=
rb
[
item_name
].
text
();
if
(
tb
==
"."
or
tb
==
"?"
)
tb
=
""
;
...
...
src/condition.cpp
View file @
30a2ebdb
...
...
@@ -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,14 +63,14 @@ 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_name
);
m_icase
=
is_
item_type_uchar
(
c
,
m_item_name
);
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
}
}];
m_single_hit
=
c
[{
{
m_item_
name
,
m_value
}
}];
}
return
this
;
...
...
src/datablock.cpp
View file @
30a2ebdb
...
...
@@ -143,13 +143,6 @@ std::tuple<datablock::iterator, bool> datablock::emplace(std::string_view name)
if
(
iequals
(
name
,
i
->
name
()))
{
is_new
=
false
;
if
(
i
!=
begin
())
{
auto
n
=
std
::
next
(
i
);
splice
(
begin
(),
*
this
,
i
,
n
);
}
break
;
}
...
...
@@ -158,25 +151,24 @@ std::tuple<datablock::iterator, bool> datablock::emplace(std::string_view name)
if
(
is_new
)
{
auto
&
c
=
emplace_back
(
name
);
c
.
set_validator
(
m_validator
,
*
this
);
i
=
insert
(
end
(),
{
name
}
);
i
->
set_validator
(
m_validator
,
*
this
);
}
assert
(
end
()
!=
begin
());
return
std
::
make_tuple
(
std
::
prev
(
end
())
,
is_new
);
assert
(
i
!=
end
());
return
std
::
make_tuple
(
i
,
is_new
);
}
std
::
vector
<
std
::
string
>
datablock
::
get_
tag
_order
()
const
std
::
vector
<
std
::
string
>
datablock
::
get_
item
_order
()
const
{
std
::
vector
<
std
::
string
>
result
;
// for entry and audit_conform on top
auto
ci
=
find_if
(
begin
(),
end
(),
[](
const
category
&
cat
)
{
return
cat
.
name
()
==
"entry"
;
});
if
(
ci
!=
end
())
{
auto
cto
=
ci
->
get_
tag
_order
();
auto
cto
=
ci
->
get_
item
_order
();
result
.
insert
(
result
.
end
(),
cto
.
begin
(),
cto
.
end
());
}
...
...
@@ -184,7 +176,7 @@ std::vector<std::string> datablock::get_tag_order() const
{
return
cat
.
name
()
==
"audit_conform"
;
});
if
(
ci
!=
end
())
{
auto
cto
=
ci
->
get_
tag
_order
();
auto
cto
=
ci
->
get_
item
_order
();
result
.
insert
(
result
.
end
(),
cto
.
begin
(),
cto
.
end
());
}
...
...
@@ -192,7 +184,7 @@ std::vector<std::string> datablock::get_tag_order() const
{
if
(
cat
.
name
()
==
"entry"
or
cat
.
name
()
==
"audit_conform"
)
continue
;
auto
cto
=
cat
.
get_
tag
_order
();
auto
cto
=
cat
.
get_
item
_order
();
result
.
insert
(
result
.
end
(),
cto
.
begin
(),
cto
.
end
());
}
...
...
@@ -253,12 +245,31 @@ void datablock::write(std::ostream &os) const
{
// If the dictionary declares an audit_conform category, put it in,
// but only if it does not exist already!
if
(
get
(
"audit_conform"
)
==
nullptr
and
m_validator
->
get_validator_for_category
(
"audit_conform"
)
!=
nullptr
)
if
(
m_validator
->
get_validator_for_category
(
"audit_conform"
)
!=
nullptr
)
{
category
auditConform
(
"audit_conform"
);
auditConform
.
emplace
({
{
"dict_name"
,
m_validator
->
name
()
},
{
"dict_version"
,
m_validator
->
version
()
}
});
auditConform
.
write
(
os
);
auto
*
audit_conform
=
get
(
"audit_conform"
);
if
(
audit_conform
==
nullptr
or
audit_conform
->
size
()
!=
1
)
// There should be one entry here, I guess
audit_conform
=
nullptr
;
else
{
// And the name and version should be filled in of course
auto
&
e
=
audit_conform
->
front
();
if
(
e
[
"dict_name"
].
empty
()
or
e
[
"dict_version"
].
empty
())
audit_conform
=
nullptr
;
}
if
(
not
audit_conform
)
{
category
auditConform
(
"audit_conform"
);
// clang-format off
auditConform
.
emplace
({
{
"dict_name"
,
m_validator
->
name
()
},
{
"dict_version"
,
m_validator
->
version
()
}
});
// clang-format on
auditConform
.
write
(
os
);
}
}
// base order on parent child relationships, parents first
...
...
@@ -327,16 +338,16 @@ void datablock::write(std::ostream &os) const
}
}
void
datablock
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
tag
_order
)
void
datablock
::
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
item_name
_order
)
{
os
<<
"data_"
<<
m_name
<<
'\n'
<<
"#
\n
"
;
std
::
vector
<
std
::
string
>
cat_order
;
for
(
auto
&
o
:
tag
_order
)
for
(
auto
&
o
:
item_name
_order
)
{
std
::
string
cat_name
,
item_name
;
std
::
tie
(
cat_name
,
item_name
)
=
split_
tag
_name
(
o
);
std
::
tie
(
cat_name
,
item_name
)
=
split_
item
_name
(
o
);
if
(
find_if
(
cat_order
.
rbegin
(),
cat_order
.
rend
(),
[
cat_name
](
const
std
::
string
&
s
)
->
bool
{
return
iequals
(
cat_name
,
s
);
})
==
cat_order
.
rend
())
cat_order
.
push_back
(
cat_name
);
...
...
@@ -349,10 +360,10 @@ void datablock::write(std::ostream &os, const std::vector<std::string> &tag_orde
continue
;
std
::
vector
<
std
::
string
>
items
;
for
(
auto
&
o
:
tag
_order
)
for
(
auto
&
o
:
item_name
_order
)
{
std
::
string
cat_name
,
item_name
;
std
::
tie
(
cat_name
,
item_name
)
=
split_
tag
_name
(
o
);
std
::
tie
(
cat_name
,
item_name
)
=
split_
item
_name
(
o
);
if
(
cat_name
==
c
)
items
.
push_back
(
item_name
);
...
...
src/dictionary_parser.cpp
View file @
30a2ebdb
...
...
@@ -50,7 +50,7 @@ class dictionary_parser : public parser
try
{
while
(
m_lookahead
!=
CIFToken
::
E
of
)
while
(
m_lookahead
!=
CIFToken
::
E
ND_OF_FILE
)
{
switch
(
m_lookahead
)
{
...
...
@@ -128,7 +128,7 @@ class dictionary_parser : public parser
datablock
::
iterator
cat
=
dict
.
end
();
match
(
CIFToken
::
SAVE_NAME
);
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
Tag
)
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
ITEM_NAME
)
{
if
(
m_lookahead
==
CIFToken
::
LOOP
)
{
...
...
@@ -136,30 +136,30 @@ class dictionary_parser : public parser
match
(
CIFToken
::
LOOP
);
std
::
vector
<
std
::
string
>
tag
s
;
while
(
m_lookahead
==
CIFToken
::
Tag
)
std
::
vector
<
std
::
string
>
item_name
s
;
while
(
m_lookahead
==
CIFToken
::
ITEM_NAME
)
{
std
::
string
catName
,
item_name
;
std
::
tie
(
catName
,
item_name
)
=
split_
tag
_name
(
m_token_value
);
std
::
tie
(
catName
,
item_name
)
=
split_
item
_name
(
m_token_value
);
if
(
cat
==
dict
.
end
())
std
::
tie
(
cat
,
std
::
ignore
)
=
dict
.
emplace
(
catName
);
else
if
(
not
iequals
(
cat
->
name
(),
catName
))
error
(
"inconsistent categories in loop_"
);
tag
s
.
push_back
(
item_name
);
match
(
CIFToken
::
Tag
);
item_name
s
.
push_back
(
item_name
);
match
(
CIFToken
::
ITEM_NAME
);
}
while
(
m_lookahead
==
CIFToken
::
V
alue
)
while
(
m_lookahead
==
CIFToken
::
V
ALUE
)
{
cat
->
emplace
({});
auto
row
=
cat
->
back
();
for
(
auto
tag
:
tag
s
)
for
(
auto
item_name
:
item_name
s
)
{
row
[
tag
]
=
m_token_value
;
match
(
CIFToken
::
V
alue
);
row
[
item_name
]
=
m_token_value
;
match
(
CIFToken
::
V
ALUE
);
}
}
...
...
@@ -168,18 +168,18 @@ class dictionary_parser : public parser
else
{
std
::
string
catName
,
item_name
;
std
::
tie
(
catName
,
item_name
)
=
split_
tag
_name
(
m_token_value
);
std
::
tie
(
catName
,
item_name
)
=
split_
item
_name
(
m_token_value
);
if
(
cat
==
dict
.
end
()
or
not
iequals
(
cat
->
name
(),
catName
))
std
::
tie
(
cat
,
std
::
ignore
)
=
dict
.
emplace
(
catName
);
match
(
CIFToken
::
Tag
);
match
(
CIFToken
::
ITEM_NAME
);
if
(
cat
->
empty
())
cat
->
emplace
({});
cat
->
back
()[
item_name
]
=
m_token_value
;
match
(
CIFToken
::
V
alue
);
match
(
CIFToken
::
V
ALUE
);
}
}
...
...
@@ -191,7 +191,7 @@ class dictionary_parser : public parser
std
::
vector
<
std
::
string
>
keys
;
for
(
auto
k
:
dict
[
"category_key"
])
keys
.
push_back
(
std
::
get
<
1
>
(
split_
tag
_name
(
k
[
"name"
].
as
<
std
::
string
>
())));
keys
.
push_back
(
std
::
get
<
1
>
(
split_
item
_name
(
k
[
"name"
].
as
<
std
::
string
>
())));
iset
groups
;
for
(
auto
g
:
dict
[
"category_group"
])
...
...
@@ -234,17 +234,17 @@ class dictionary_parser : public parser
// collect the dict from our dataBlock and construct validators
for
(
auto
i
:
dict
[
"item"
])
{
std
::
string
tagName
,
category
,
mandatory
;
cif
::
tie
(
tagName
,
category
,
mandatory
)
=
i
.
get
(
"name"
,
"category_id"
,
"mandatory_code"
);
std
::
string
item
,
category
,
mandatory
;
cif
::
tie
(
item
,
category
,
mandatory
)
=
i
.
get
(
"name"
,
"category_id"
,
"mandatory_code"
);
std
::
string
cat_name
,
item_name
;
std
::
tie
(
cat_name
,
item_name
)
=
split_
tag_name
(
tagName
);
std
::
tie
(
cat_name
,
item_name
)
=
split_
item_name
(
item
);
if
(
cat_name
.
empty
()
or
item_name
.
empty
())
error
(
"Invalid
tag name in _item.name "
+
tagName
);
error
(
"Invalid
item name in _item.name "
+
item
);
if
(
not
iequals
(
category
,
cat_name
)
and
not
(
category
.
empty
()
or
category
==
"?"
))
error
(
"specified category id does match the implicit category name for
tag '"
+
tagName
+
'\''
);
error
(
"specified category id does match the implicit category name for
item '"
+
item
+
'\''
);
else
category
=
cat_name
;
...
...
@@ -260,22 +260,22 @@ class dictionary_parser : public parser
{
if
(
VERBOSE
>
2
)
{
std
::
cerr
<<
"inconsistent mandatory value for "
<<
tagName
<<
" in dictionary
\n
"
;
std
::
cerr
<<
"inconsistent mandatory value for "
<<
item
<<
" in dictionary
\n
"
;
if
(
iequals
(
tagName
,
saveFrameName
))
if
(
iequals
(
item
,
saveFrameName
))
std
::
cerr
<<
"choosing "
<<
mandatory
<<
'\n'
;
else
std
::
cerr
<<
"choosing "
<<
(
vi
->
m_mandatory
?
"Y"
:
"N"
)
<<
'\n'
;
}
if
(
iequals
(
tagName
,
saveFrameName
))
if
(
iequals
(
item
,
saveFrameName
))
vi
->
m_mandatory
=
(
iequals
(
mandatory
,
"yes"
));
}
if
(
vi
->
m_type
!=
nullptr
and
tv
!=
nullptr
and
vi
->
m_type
!=
tv
)
{
if
(
VERBOSE
>
1
)
std
::
cerr
<<
"inconsistent type for "
<<
tagName
<<
" in dictionary
\n
"
;
std
::
cerr
<<
"inconsistent type for "
<<
item
<<
" in dictionary
\n
"
;
}
// vi->mMandatory = (iequals(mandatory, "yes"));
...
...
@@ -358,7 +358,7 @@ class dictionary_parser : public parser
}
size_t
ix
=
linkIndex
.
at
(
key
);
addLink
(
ix
,
piv
->
m_
tag
,
civ
->
m_tag
);
addLink
(
ix
,
piv
->
m_
item_name
,
civ
->
m_item_name
);
}
// Only process inline linked items if the linked group list is absent
...
...
@@ -386,7 +386,7 @@ class dictionary_parser : public parser
}
size_t
ix
=
linkIndex
.
at
(
key
);
addLink
(
ix
,
piv
->
m_
tag
,
civ
->
m_tag
);
addLink
(
ix
,
piv
->
m_
item_name
,
civ
->
m_item_name
);
}
}
...
...
@@ -417,7 +417,7 @@ class dictionary_parser : public parser
for
(
auto
&
iv
:
cv
.
m_item_validators
)
{
if
(
iv
.
m_type
==
nullptr
and
cif
::
VERBOSE
>=
0
)
std
::
cerr
<<
"Missing item_type for "
<<
iv
.
m_
tag
<<
'\n'
;
std
::
cerr
<<
"Missing item_type for "
<<
iv
.
m_
item_name
<<
'\n'
;
}
}
}
...
...
src/file.cpp
View file @
30a2ebdb
...
...
@@ -158,13 +158,6 @@ std::tuple<file::iterator, bool> file::emplace(std::string_view name)
if
(
iequals
(
name
,
i
->
name
()))
{
is_new
=
false
;
if
(
i
!=
begin
())
{
auto
n
=
std
::
next
(
i
);
splice
(
begin
(),
*
this
,
i
,
n
);
}
break
;
}
...
...
@@ -173,12 +166,12 @@ std::tuple<file::iterator, bool> file::emplace(std::string_view name)
if
(
is_new
)
{
auto
&
db
=
emplace_back
(
name
);
db
.
set_validator
(
m_validator
);
i
=
insert
(
end
(),
{
name
}
);
i
->
set_validator
(
m_validator
);
}
assert
(
begin
()
!=
end
());
return
std
::
make_tuple
(
std
::
prev
(
end
())
,
is_new
);
assert
(
i
!=
end
());
return
std
::
make_tuple
(
i
,
is_new
);
}
void
file
::
load
(
const
std
::
filesystem
::
path
&
p
)
...
...
src/item.cpp
View file @
30a2ebdb
...
...
@@ -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/model.cpp
View file @
30a2ebdb
...
...
@@ -163,9 +163,9 @@ int atom::atom_impl::get_charge() const
// const std::string atom::atom_impl::get_property(const std::string_view name) const
// {
// for (auto &&[
tag
, ref] : mCachedRefs)
// for (auto &&[
item_name
, ref] : mCachedRefs)
// {
// if (
tag
== name)
// if (
item_name
== name)
// return ref.as<std::string>();
// }
...
...
@@ -175,9 +175,9 @@ int atom::atom_impl::get_charge() const
// void atom::atom_impl::set_property(const std::string_view name, const std::string &value)
// {
// for (auto &&[
tag
, ref] : mCachedRefs)
// for (auto &&[
item_name
, ref] : mCachedRefs)
// {
// if (
tag
!= name)
// if (
item_name
!= name)
// continue;
// ref = value;
...
...
src/parser.cpp
View file @
30a2ebdb
...
...
@@ -269,7 +269,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
{
const
auto
kEOF
=
std
::
char_traits
<
char
>::
eof
();
CIFToken
result
=
CIFToken
::
U
nknown
;
CIFToken
result
=
CIFToken
::
U
NKNOWN
;
int
quoteChar
=
0
;
State
state
=
State
::
Start
;
m_bol
=
false
;
...
...
@@ -279,7 +279,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
reserved_words_automaton
dag
;
while
(
result
==
CIFToken
::
U
nknown
)
while
(
result
==
CIFToken
::
U
NKNOWN
)
{
auto
ch
=
get_next_char
();
...
...
@@ -287,7 +287,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
{
case
State
:
:
Start
:
if
(
ch
==
kEOF
)
result
=
CIFToken
::
E
of
;
result
=
CIFToken
::
E
ND_OF_FILE
;
else
if
(
ch
==
'\n'
)
{
m_bol
=
true
;
...
...
@@ -298,9 +298,9 @@ sac_parser::CIFToken sac_parser::get_next_token()
else
if
(
ch
==
'#'
)
state
=
State
::
Comment
;
else
if
(
ch
==
'_'
)
state
=
State
::
Tag
;
state
=
State
::
ItemName
;
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
==
'"'
)
...
...
@@ -316,7 +316,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
case
State
:
:
White
:
if
(
ch
==
kEOF
)
result
=
CIFToken
::
E
of
;
result
=
CIFToken
::
E
ND_OF_FILE
;
else
if
(
not
is_space
(
ch
))
{
state
=
State
::
Start
;
...
...
@@ -335,7 +335,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
m_token_buffer
.
clear
();
}
else
if
(
ch
==
kEOF
)
result
=
CIFToken
::
E
of
;
result
=
CIFToken
::
E
ND_OF_FILE
;
else
if
(
not
is_any_print
(
ch
))
error
(
"invalid character in comment"
);
break
;
...
...
@@ -344,29 +344,29 @@ sac_parser::CIFToken sac_parser::get_next_token()
if
(
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
V
alue
;
result
=
CIFToken
::
V
ALUE
;
}
else
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
);
m_token_value
=
std
::
string_view
(
m_token_buffer
.
data
()
+
1
,
m_token_buffer
.
size
()
-
3
);
result
=
CIFToken
::
V
alue
;
result
=
CIFToken
::
V
ALUE
;
}
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
...
...
@@ -387,7 +387,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
if
(
is_white
(
ch
))
{
retract
();
result
=
CIFToken
::
V
alue
;
result
=
CIFToken
::
V
ALUE
;
if
(
m_token_buffer
.
size
()
<
2
)
error
(
"Invalid quoted string token"
);
...
...
@@ -403,11 +403,11 @@ sac_parser::CIFToken sac_parser::get_next_token()
error
(
"invalid character in quoted string"
);
break
;
case
State
:
:
Tag
:
case
State
:
:
ItemName
:
if
(
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
Tag
;
result
=
CIFToken
::
ITEM_NAME
;
m_token_value
=
std
::
string_view
(
m_token_buffer
.
data
(),
m_token_buffer
.
size
());
}
break
;
...
...
@@ -422,7 +422,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
if
(
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
V
alue
;
result
=
CIFToken
::
V
ALUE
;
m_token_value
=
std
::
string_view
(
m_token_buffer
.
data
(),
m_token_buffer
.
size
());
}
else
...
...
@@ -467,7 +467,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
if
(
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
V
alue
;
result
=
CIFToken
::
V
ALUE
;
m_token_value
=
std
::
string_view
(
m_token_buffer
.
data
(),
m_token_buffer
.
size
());
break
;
}
...
...
@@ -483,7 +483,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
if
(
VERBOSE
>=
5
)
{
std
::
cerr
<<
get_token_name
(
result
);
if
(
result
!=
CIFToken
::
E
of
)
if
(
result
!=
CIFToken
::
E
ND_OF_FILE
)
std
::
cerr
<<
" "
<<
std
::
quoted
(
m_token_value
);
std
::
cerr
<<
'\n'
;
}
...
...
@@ -710,7 +710,7 @@ bool sac_parser::parse_single_datablock(const std::string &datablock, const data
void
sac_parser
::
parse_file
()
{
while
(
m_lookahead
!=
CIFToken
::
E
of
)
while
(
m_lookahead
!=
CIFToken
::
E
ND_OF_FILE
)
{
switch
(
m_lookahead
)
{
...
...
@@ -735,10 +735,10 @@ void sac_parser::parse_file()
void
sac_parser
::
parse_global
()
{
match
(
CIFToken
::
GLOBAL
);
while
(
m_lookahead
==
CIFToken
::
Tag
)
while
(
m_lookahead
==
CIFToken
::
ITEM_NAME
)
{
match
(
CIFToken
::
Tag
);
match
(
CIFToken
::
V
alue
);
match
(
CIFToken
::
ITEM_NAME
);
match
(
CIFToken
::
V
ALUE
);
}
}
...
...
@@ -747,7 +747,7 @@ void sac_parser::parse_datablock()
static
const
std
::
string
kUnitializedCategory
(
"<invalid>"
);
std
::
string
cat
=
kUnitializedCategory
;
// intial value acts as a guard for empty category names
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
Tag
or
m_lookahead
==
CIFToken
::
SAVE_NAME
)
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
ITEM_NAME
or
m_lookahead
==
CIFToken
::
SAVE_NAME
)
{
switch
(
m_lookahead
)
{
...
...
@@ -757,12 +757,12 @@ void sac_parser::parse_datablock()
match
(
CIFToken
::
LOOP
);
std
::
vector
<
std
::
string
>
tag
s
;
std
::
vector
<
std
::
string
>
item_name
s
;
while
(
m_lookahead
==
CIFToken
::
Tag
)
while
(
m_lookahead
==
CIFToken
::
ITEM_NAME
)
{
std
::
string
catName
,
itemName
;
std
::
tie
(
catName
,
itemName
)
=
split_
tag
_name
(
m_token_value
);
std
::
tie
(
catName
,
itemName
)
=
split_
item
_name
(
m_token_value
);
if
(
cat
==
kUnitializedCategory
)
{
...
...
@@ -772,19 +772,19 @@ void sac_parser::parse_datablock()
else
if
(
not
iequals
(
cat
,
catName
))
error
(
"inconsistent categories in loop_"
);
tag
s
.
push_back
(
itemName
);
item_name
s
.
push_back
(
itemName
);
match
(
CIFToken
::
Tag
);
match
(
CIFToken
::
ITEM_NAME
);
}
while
(
m_lookahead
==
CIFToken
::
V
alue
)
while
(
m_lookahead
==
CIFToken
::
V
ALUE
)
{
produce_row
();
for
(
auto
tag
:
tag
s
)
for
(
auto
item_name
:
item_name
s
)
{
produce_item
(
cat
,
tag
,
m_token_value
);
match
(
CIFToken
::
V
alue
);
produce_item
(
cat
,
item_name
,
m_token_value
);
match
(
CIFToken
::
V
ALUE
);
}
}
...
...
@@ -792,10 +792,10 @@ void sac_parser::parse_datablock()
break
;
}
case
CIFToken
:
:
Tag
:
case
CIFToken
:
:
ITEM_NAME
:
{
std
::
string
catName
,
itemName
;
std
::
tie
(
catName
,
itemName
)
=
split_
tag
_name
(
m_token_value
);
std
::
tie
(
catName
,
itemName
)
=
split_
item
_name
(
m_token_value
);
if
(
not
iequals
(
cat
,
catName
))
{
...
...
@@ -804,11 +804,11 @@ void sac_parser::parse_datablock()
produce_row
();
}
match
(
CIFToken
::
Tag
);
match
(
CIFToken
::
ITEM_NAME
);
produce_item
(
cat
,
itemName
,
m_token_value
);
match
(
CIFToken
::
V
alue
);
match
(
CIFToken
::
V
ALUE
);
break
;
}
...
...
src/pdb/pdb2cif_remark_3.cpp
View file @
30a2ebdb
...
...
@@ -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 @
30a2ebdb
...
...
@@ -237,20 +237,20 @@ 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
>>
{
for
(
auto
[
item_name
,
prec
]
:
std
::
vector
<
std
::
tuple
<
std
::
string_view
,
std
::
string
::
size_type
>>
{
{
"cartn_x"
,
3
},
{
"cartn_y"
,
3
},
{
"cartn_z"
,
3
},
{
"occupancy"
,
2
},
{
"b_iso_or_equiv"
,
2
}
})
{
if
(
row
[
tag
].
empty
())
if
(
row
[
item_name
].
empty
())
continue
;
float
v
;
auto
s
=
row
.
get
<
std
::
string
>
(
tag
);
auto
s
=
row
.
get
<
std
::
string
>
(
item_name
);
if
(
auto
[
ptr
,
ec
]
=
cif
::
from_chars
(
s
.
data
(),
s
.
data
()
+
s
.
length
(),
v
);
ec
!=
std
::
errc
())
continue
;
...
...
@@ -259,7 +259,7 @@ void checkAtomRecords(datablock &db)
char
b
[
12
];
if
(
auto
[
ptr
,
ec
]
=
cif
::
to_chars
(
b
,
b
+
sizeof
(
b
),
v
,
cif
::
chars_format
::
fixed
,
prec
);
ec
==
std
::
errc
())
row
.
assign
(
tag
,
{
b
,
static_cast
<
std
::
string
::
size_type
>
(
ptr
-
b
)
},
false
,
false
);
row
.
assign
(
item_name
,
{
b
,
static_cast
<
std
::
string
::
size_type
>
(
ptr
-
b
)
},
false
,
false
);
}
}
}
...
...
@@ -267,22 +267,22 @@ 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
item_name
:
atom_site
.
get_item
s
())
{
if
(
cv
->
get_validator_for_item
(
tag
)
!=
nullptr
)
if
(
cv
->
get_validator_for_item
(
item_name
)
!=
nullptr
)
continue
;
auto
r
=
atom_site
.
find_first
(
key
(
tag
)
!=
null
);
auto
r
=
atom_site
.
find_first
(
key
(
item_name
)
!=
null
);
if
(
not
r
)
{
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Dropping unknown
column "
<<
tag
<<
'\n'
;
std
::
clog
<<
"Dropping unknown
item "
<<
item_name
<<
'\n'
;
atom_site
.
remove_
column
(
tag
);
atom_site
.
remove_
item
(
item_name
);
}
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
(
item_name
)
<<
" 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,21 +731,21 @@ 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
item_name
:
cat
.
get_item
s
())
{
auto
iv
=
cv
->
get_validator_for_item
(
tag
);
if
(
iv
)
// know, must be OK then
auto
iv
=
cv
->
get_validator_for_item
(
item_name
);
if
(
iv
)
// know, must be OK then
`
continue
;
iv
=
cv
->
get_validator_for_aliased_item
(
tag
);
iv
=
cv
->
get_validator_for_aliased_item
(
item_name
);
if
(
not
iv
)
continue
;
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Renaming "
<<
tag
<<
" to "
<<
iv
->
m_tag
<<
" in category "
<<
cat
.
name
()
<<
'\n'
;
cat
.
rename_
column
(
tag
,
iv
->
m_tag
);
std
::
clog
<<
"Renaming "
<<
item_name
<<
" to "
<<
iv
->
m_item_name
<<
" in category "
<<
cat
.
name
()
<<
'\n'
;
cat
.
rename_
item
(
item_name
,
iv
->
m_item_name
);
}
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
item_name
:
cat
.
get_items
())
{
auto
iv
=
cv
->
get_validator_for_item
(
item_name
);
if
(
not
iv
)
continue
;
auto
ix
=
cat
.
get_item_ix
(
item_name
);
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 "
<<
item_name
<<
" 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 @
30a2ebdb
...
...
@@ -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 @
30a2ebdb
...
...
@@ -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/text.cpp
View file @
30a2ebdb
...
...
@@ -215,19 +215,19 @@ std::string trim_copy(std::string_view s)
// --------------------------------------------------------------------
std
::
tuple
<
std
::
string
,
std
::
string
>
split_
tag_name
(
std
::
string_view
tag
)
std
::
tuple
<
std
::
string
,
std
::
string
>
split_
item_name
(
std
::
string_view
item_name
)
{
if
(
tag
.
empty
())
throw
std
::
runtime_error
(
"empty
tag
"
);
if
(
tag
[
0
]
!=
'_'
)
throw
std
::
runtime_error
(
"
tag '"
+
std
::
string
{
tag
}
+
"' does not start with underscore"
);
if
(
item_name
.
empty
())
throw
std
::
runtime_error
(
"empty
item_name
"
);
if
(
item_name
[
0
]
!=
'_'
)
throw
std
::
runtime_error
(
"
item_name '"
+
std
::
string
{
item_name
}
+
"' does not start with underscore"
);
auto
s
=
tag
.
find
(
'.'
);
auto
s
=
item_name
.
find
(
'.'
);
if
(
s
==
std
::
string
::
npos
)
// throw std::runtime_error("
tag does not contain dot (" + std::string{ tag
} + ')');
return
std
::
tuple
<
std
::
string
,
std
::
string
>
{
""
,
tag
.
substr
(
1
)
};
// throw std::runtime_error("
item_name does not contain dot (" + std::string{ item_name
} + ')');
return
std
::
tuple
<
std
::
string
,
std
::
string
>
{
""
,
item_name
.
substr
(
1
)
};
else
return
std
::
tuple
<
std
::
string
,
std
::
string
>
{
tag
.
substr
(
1
,
s
-
1
),
tag
.
substr
(
s
+
1
)};
return
std
::
tuple
<
std
::
string
,
std
::
string
>
{
item_name
.
substr
(
1
,
s
-
1
),
item_name
.
substr
(
s
+
1
)};
}
// --------------------------------------------------------------------
...
...
src/validate.cpp
View file @
30a2ebdb
...
...
@@ -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
;
}
...
...
@@ -196,39 +196,26 @@ int type_validator::compare(std::string_view a, std::string_view b) const
// --------------------------------------------------------------------
// void ValidateItem::addLinked(ValidateItem* parent, const std::string& parentItem, const std::string& childItem)
//{
//// if (mParent != nullptr and VERBOSE)
//// cerr << "replacing parent in " << mCategory->m_name << " from " << mParent->mCategory->m_name << " to " << parent->mCategory->m_name << endl;
//// mParent = parent;
//
// if (m_type == nullptr and parent != nullptr)
// m_type = parent->m_type;
//
// if (parent != nullptr)
// {
// mLinked.push_back({parent, parentItem, childItem});
//
// parent->mChildren.insert(this);
////
//// if (mCategory->mKeys == std::vector<std::string>{mTag})
//// parent->mForeignKeys.insert(this);
// }
//}
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_item_name
);
}
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,27 +223,27 @@ void item_validator::operator()(std::string_view value) const
void
category_validator
::
add_item_validator
(
item_validator
&&
v
)
{
if
(
v
.
m_mandatory
)
m_mandatory_
fields
.
insert
(
v
.
m_tag
);
m_mandatory_
items
.
insert
(
v
.
m_item_name
);
v
.
m_category
=
this
;
auto
r
=
m_item_validators
.
insert
(
std
::
move
(
v
));
if
(
not
r
.
second
and
VERBOSE
>=
4
)
std
::
cout
<<
"Could not add validator for item "
<<
v
.
m_
tag
<<
" to category "
<<
m_name
<<
'\n'
;
std
::
cout
<<
"Could not add validator for item "
<<
v
.
m_
item_name
<<
" to category "
<<
m_name
<<
'\n'
;
}
const
item_validator
*
category_validator
::
get_validator_for_item
(
std
::
string_view
tag
)
const
const
item_validator
*
category_validator
::
get_validator_for_item
(
std
::
string_view
item_name
)
const
{
const
item_validator
*
result
=
nullptr
;
auto
i
=
m_item_validators
.
find
(
item_validator
{
std
::
string
(
tag
)
});
auto
i
=
m_item_validators
.
find
(
item_validator
{
std
::
string
(
item_name
)
});
if
(
i
!=
m_item_validators
.
end
())
result
=
&*
i
;
else
if
(
VERBOSE
>
4
)
std
::
cout
<<
"No validator for
tag "
<<
tag
<<
'\n'
;
std
::
cout
<<
"No validator for
item "
<<
item_name
<<
'\n'
;
return
result
;
}
const
item_validator
*
category_validator
::
get_validator_for_aliased_item
(
std
::
string_view
tag
)
const
const
item_validator
*
category_validator
::
get_validator_for_aliased_item
(
std
::
string_view
item_name
)
const
{
const
item_validator
*
result
=
nullptr
;
...
...
@@ -264,8 +251,8 @@ 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
)
const
auto
&
[
cat
,
name
]
=
split_
item
_name
(
ai
.
m_name
);
if
(
iequals
(
name
,
item_name
)
and
iequals
(
cat
,
m_name
)
)
{
result
=
&
iv
;
break
;
...
...
@@ -317,19 +304,19 @@ const category_validator *validator::get_validator_for_category(std::string_view
return
result
;
}
item_validator
*
validator
::
get_validator_for_item
(
std
::
string_view
tag
)
const
item_validator
*
validator
::
get_validator_for_item
(
std
::
string_view
item_name
)
const
{
item_validator
*
result
=
nullptr
;
std
::
string
cat
,
item
;
std
::
tie
(
cat
,
item
)
=
split_
tag_name
(
tag
);
std
::
tie
(
cat
,
item
)
=
split_
item_name
(
item_name
);
auto
*
cv
=
get_validator_for_category
(
cat
);
if
(
cv
!=
nullptr
)
result
=
const_cast
<
item_validator
*>
(
cv
->
get_validator_for_item
(
item
));
if
(
result
==
nullptr
and
VERBOSE
>
4
)
std
::
cout
<<
"No validator for item "
<<
tag
<<
'\n'
;
std
::
cout
<<
"No validator for item "
<<
item_name
<<
'\n'
;
return
result
;
}
...
...
@@ -354,11 +341,11 @@ void validator::add_link_validator(link_validator &&v)
auto
piv
=
pcv
->
get_validator_for_item
(
v
.
m_parent_keys
[
i
]);
if
(
piv
==
nullptr
)
throw
std
::
runtime_error
(
"unknown parent
tag
_"
+
v
.
m_parent_category
+
'.'
+
v
.
m_parent_keys
[
i
]);
throw
std
::
runtime_error
(
"unknown parent
item
_"
+
v
.
m_parent_category
+
'.'
+
v
.
m_parent_keys
[
i
]);
auto
civ
=
ccv
->
get_validator_for_item
(
v
.
m_child_keys
[
i
]);
if
(
civ
==
nullptr
)
throw
std
::
runtime_error
(
"unknown child
tag
_"
+
v
.
m_child_category
+
'.'
+
v
.
m_child_keys
[
i
]);
throw
std
::
runtime_error
(
"unknown child
item
_"
+
v
.
m_child_category
+
'.'
+
v
.
m_child_keys
[
i
]);
if
(
civ
->
m_type
==
nullptr
and
piv
->
m_type
!=
nullptr
)
const_cast
<
item_validator
*>
(
civ
)
->
m_type
=
piv
->
m_type
;
...
...
@@ -373,7 +360,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 +373,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 +469,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