Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
libcifpp
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
libcifpp
Commits
2792caec
Unverified
Commit
2792caec
authored
Jan 23, 2024
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
renaming field and column to item
parent
fb2b1e98
Show whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
813 additions
and
480 deletions
+813
-480
include/cif++/category.hpp
+200
-131
include/cif++/condition.hpp
+42
-33
include/cif++/item.hpp
+9
-9
include/cif++/iterator.hpp
+26
-26
include/cif++/model.hpp
+7
-7
include/cif++/parser.hpp
+2
-2
include/cif++/pdb.hpp
+41
-0
include/cif++/row.hpp
+41
-41
include/cif++/validate.hpp
+134
-15
src/category.cpp
+114
-115
src/condition.cpp
+9
-9
src/item.cpp
+5
-5
src/parser.cpp
+5
-5
src/pdb/pdb2cif_remark_3.cpp
+2
-2
src/pdb/reconstruct.cpp
+43
-18
src/pdb/validate-pdbx.cpp
+60
-18
src/row.cpp
+11
-11
src/validate.cpp
+62
-33
No files found.
include/cif++/category.hpp
View file @
2792caec
...
@@ -71,7 +71,7 @@ class duplicate_key_error : public std::runtime_error
...
@@ -71,7 +71,7 @@ class duplicate_key_error : public std::runtime_error
};
};
/// @brief A missing_key_error is thrown when an attempt is made
/// @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
class
missing_key_error
:
public
std
::
runtime_error
{
{
public
:
public
:
...
@@ -156,8 +156,16 @@ class category
...
@@ -156,8 +156,16 @@ class category
// --------------------------------------------------------------------
// --------------------------------------------------------------------
const
std
::
string
&
name
()
const
{
return
m_name
;
}
///< Returns the name of the 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
/// @brief Set the validator for this category to @a v
/// @param v The category_validator to assign. A nullptr value is allowed.
/// @param v The category_validator to assign. A nullptr value is allowed.
...
@@ -301,12 +309,12 @@ class category
...
@@ -301,12 +309,12 @@ class category
using
key_type
=
row_initializer
;
using
key_type
=
row_initializer
;
/// @brief Return a row_handle for the row specified by \a key
/// @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
/// @return The row found in the index, or an undefined row_handle
row_handle
operator
[](
const
key_type
&
key
);
row_handle
operator
[](
const
key_type
&
key
);
/// @brief Return a const row_handle for the row specified by \a 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
/// @return The row found in the index, or an undefined row_handle
const
row_handle
operator
[](
const
key_type
&
key
)
const
const
row_handle
operator
[](
const
key_type
&
key
)
const
{
{
...
@@ -323,13 +331,13 @@ class category
...
@@ -323,13 +331,13 @@ class category
/// std::cout << name << ": " << value << '\n';
/// std::cout << name << ": " << value << '\n';
/// @endcode
/// @endcode
///
///
/// @tparam Ts The types for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
column
s requested
/// @param names The names for the
item
s requested
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
const
category
,
Ts
...
>
rows
(
Ns
...
names
)
const
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
...
});
return
iterator_proxy
<
const
category
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...
});
}
}
...
@@ -340,19 +348,19 @@ class category
...
@@ -340,19 +348,19 @@ class category
/// for (const auto &[name, value] : cat.rows<std::string,int>("item_name", "item_value"))
/// for (const auto &[name, value] : cat.rows<std::string,int>("item_name", "item_value"))
/// std::cout << name << ": " << value << '\n';
/// 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"))
/// for (int id : cat.rows<int>("id"))
/// std::cout << id << '\n';
/// std::cout << id << '\n';
/// @endcode
/// @endcode
///
///
/// @tparam Ts The types for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
column
s requested
/// @param names The names for the
item
s requested
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
category
,
Ts
...
>
rows
(
Ns
...
names
)
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
...
});
return
iterator_proxy
<
category
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...
});
}
}
...
@@ -420,14 +428,14 @@ class category
...
@@ -420,14 +428,14 @@ class category
/// @endcode
/// @endcode
///
///
/// @param cond The condition for the query
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
column
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
category
,
Ts
...
>
find
(
condition
&&
cond
,
Ns
...
names
)
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
)...);
return
find
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...);
}
}
...
@@ -435,14 +443,14 @@ class category
...
@@ -435,14 +443,14 @@ class category
/// iterator can be used in a structured binding context.
/// iterator can be used in a structured binding context.
///
///
/// @param cond The condition for the query
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
column
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
const
category
,
Ts
...
>
find
(
condition
&&
cond
,
Ns
...
names
)
const
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
)...);
return
find
<
Ts
...
>
(
cbegin
(),
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...);
}
}
...
@@ -451,14 +459,14 @@ class category
...
@@ -451,14 +459,14 @@ class category
///
///
/// @param pos Iterator pointing to the location where to start
/// @param pos Iterator pointing to the location where to start
/// @param cond The condition for the query
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
column
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
category
,
Ts
...
>
find
(
const_iterator
pos
,
condition
&&
cond
,
Ns
...
names
)
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
)...
};
return
{
*
this
,
pos
,
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...
};
}
}
...
@@ -467,14 +475,14 @@ class category
...
@@ -467,14 +475,14 @@ class category
///
///
/// @param pos Iterator pointing to the location where to start
/// @param pos Iterator pointing to the location where to start
/// @param cond The condition for the query
/// @param cond The condition for the query
/// @tparam Ts The types for the
column
s requested
/// @tparam Ts The types for the
item
s requested
/// @param names The names for the
column
s requested
/// @param names The names for the
item
s requested
/// @return A special iterator that loops over all elements that match.
/// @return A special iterator that loops over all elements that match.
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
const
category
,
Ts
...
>
find
(
const_iterator
pos
,
condition
&&
cond
,
Ns
...
names
)
const
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
)...
};
return
{
*
this
,
pos
,
std
::
move
(
cond
),
std
::
forward
<
Ns
>
(
names
)...
};
}
}
...
@@ -529,30 +537,30 @@ class category
...
@@ -529,30 +537,30 @@ class category
return
*
h
.
begin
();
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
/// matches @a cond. Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The type to use for the result
/// @tparam The type to use for the result
/// @param cond The condition to search for
/// @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
/// @return The value found
template
<
typename
T
>
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.
/// matches @a cond when starting to search at @a pos.
/// Throws @a multiple_results_error if there are is not exactly one row
/// Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The type to use for the result
/// @tparam The type to use for the result
/// @param pos The location to start the search
/// @param pos The location to start the search
/// @param cond The condition to search for
/// @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
/// @return The value found
template
<
typename
T
,
std
::
enable_if_t
<
not
is_optional_v
<
T
>
,
int
>
=
0
>
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
)
if
(
h
.
size
()
!=
1
)
throw
multiple_results_error
();
throw
multiple_results_error
();
...
@@ -560,18 +568,18 @@ class category
...
@@ -560,18 +568,18 @@ class category
return
*
h
.
begin
();
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.
/// matches @a cond when starting to search at @a pos.
/// If the row was not found, an empty value is returned.
/// If the row was not found, an empty value is returned.
/// @tparam The type to use for the result
/// @tparam The type to use for the result
/// @param pos The location to start the search
/// @param pos The location to start the search
/// @param cond The condition to search for
/// @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
/// @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
>
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
)
if
(
h
.
size
()
>
1
)
throw
multiple_results_error
();
throw
multiple_results_error
();
...
@@ -582,34 +590,34 @@ class category
...
@@ -582,34 +590,34 @@ class category
return
*
h
.
begin
();
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
/// for the single row that matches @a cond
/// Throws @a multiple_results_error if there are is not exactly one row
/// Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The types to use for the resulting tuple
/// @tparam The types to use for the resulting tuple
/// @param cond The condition to search for
/// @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...>
/// @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
>>
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
(
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
column
names should be const char");
// 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
>
(
column
s
)...);
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
/// 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
/// Throws @a multiple_results_error if there are is not exactly one row
/// @tparam The types to use for the resulting tuple
/// @tparam The types to use for the resulting tuple
/// @param pos The location to start the search
/// @param pos The location to start the search
/// @param cond The condition to search for
/// @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...>
/// @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
>>
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"
);
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
>
(
column
s
)...);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
item
s
)...);
if
(
h
.
size
()
!=
1
)
if
(
h
.
size
()
!=
1
)
throw
multiple_results_error
();
throw
multiple_results_error
();
...
@@ -658,74 +666,74 @@ class category
...
@@ -658,74 +666,74 @@ class category
return
h
.
empty
()
?
row_handle
{}
:
*
h
.
begin
();
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
/// @tparam The type of the value to return
/// @param cond The condition to search for
/// @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
/// @return The value found or a default constructed value if not found
template
<
typename
T
>
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
/// when starting the search at @a pos
/// @tparam The type of the value to return
/// @tparam The type of the value to return
/// @param pos The location to start searching
/// @param pos The location to start searching
/// @param cond The condition to search for
/// @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
/// @return The value found or a default constructed value if not found
template
<
typename
T
>
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
();
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
/// @tparam The types of the values to return
/// @param cond The condition to search for
/// @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
/// @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
>>
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
(
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
column
names should be const char");
// 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
>
(
column
s
)...);
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
/// when starting the search at @a pos
/// @tparam The types of the values to return
/// @tparam The types of the values to return
/// @param pos The location to start searching
/// @param pos The location to start searching
/// @param cond The condition to search for
/// @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
/// @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
>>
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"
);
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
>
(
column
s
)...);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
move
(
cond
),
std
::
forward
<
Cs
>
(
item
s
)...);
return
h
.
empty
()
?
std
::
tuple
<
Ts
...
>
{}
:
*
h
.
begin
();
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
/// @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
/// @param cond The condition to search for
/// @return The value found or the minimal value for the type
/// @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
>
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
();
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
)
if
(
result
<
v
)
result
=
v
;
result
=
v
;
...
@@ -734,27 +742,27 @@ class category
...
@@ -734,27 +742,27 @@ class category
return
result
;
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
/// @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
/// @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
>
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
/// @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
/// @param cond The condition to search for
/// @return The value found or the maximum value for the type
/// @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
>
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
();
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
)
if
(
result
>
v
)
result
=
v
;
result
=
v
;
...
@@ -763,14 +771,14 @@ class category
...
@@ -763,14 +771,14 @@ class category
return
result
;
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
/// @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
/// @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
>
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
/// @brief Return whether a row exists that matches condition @a cond
...
@@ -918,7 +926,7 @@ class category
...
@@ -918,7 +926,7 @@ class category
for
(
auto
i
=
b
;
i
!=
e
;
++
i
)
for
(
auto
i
=
b
;
i
!=
e
;
++
i
)
{
{
// item_value *new_item = this->create_item(*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
(...)
catch
(...)
...
@@ -956,7 +964,7 @@ class category
...
@@ -956,7 +964,7 @@ class category
// --------------------------------------------------------------------
// --------------------------------------------------------------------
/// \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 tag in the rows that match \a cond to value \a value
/// making sure the linked categories are updated according to the link.
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
/// and unique. If they are not, the child category rows are split.
...
@@ -969,7 +977,7 @@ class category
...
@@ -969,7 +977,7 @@ class category
update_value
(
rows
,
tag
,
value
);
update_value
(
rows
,
tag
,
value
);
}
}
/// \brief Update a single
column
named @a tag in @a rows to value \a value
/// \brief Update a single
item
named @a tag in @a rows to value \a value
/// making sure the linked categories are updated according to the link.
/// making sure the linked categories are updated according to the link.
/// That means, child categories are updated if the links are absolute
/// That means, child categories are updated if the links are absolute
/// and unique. If they are not, the child category rows are split.
/// and unique. If they are not, the child category rows are split.
...
@@ -977,83 +985,144 @@ class category
...
@@ -977,83 +985,144 @@ class category
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
tag
,
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
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
;
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
;
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
)
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
;
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
/// @param ix The index number
/// @return The name of the
column
/// @return The name of the
item
std
::
string_view
get_
column
_name
(
uint16_t
ix
)
const
std
::
string_view
get_
item
_name
(
uint16_t
ix
)
const
{
{
if
(
ix
>=
m_
column
s
.
size
())
if
(
ix
>=
m_
item
s
.
size
())
throw
std
::
out_of_range
(
"
column
index is out of range"
);
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
/// @brief Make sure a
item with name @a item
_name is known and return its index number
/// @param
column_name The name of the column
/// @param
item_name The name of the item
/// @return The index number of the
column
/// @return The index number of the
item
uint16_t
add_
column
(
std
::
string_view
column
_name
)
uint16_t
add_
item
(
std
::
string_view
item
_name
)
{
{
using
namespace
std
::
literals
;
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
;
const
item_validator
*
item_validator
=
nullptr
;
if
(
m_cat_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
)
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
;
return
result
;
}
}
/** @brief Remove
column
name @a colum_name
/** @brief Remove
item
name @a colum_name
* @param
column_name The column
to be removed
* @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 */
/** @brief Rename
item
@a from_name to @a to_name */
void
rename_
column
(
std
::
string_view
from_name
,
std
::
string_view
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
/// @brief Return whether a
item
with name @a name exists in this category
/// @param name The name of the
column
/// @param name The name of the
item
/// @return True if the
column
exists
/// @return True if the
item
exists
bool
has_
column
(
std
::
string_view
name
)
const
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
/// @brief Return the cif::iset of
item
s in this category
iset
get_
column
s
()
const
;
iset
get_
item
s
()
const
;
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -1069,23 +1138,23 @@ class category
...
@@ -1069,23 +1138,23 @@ class category
// --------------------------------------------------------------------
// --------------------------------------------------------------------
/// This function returns effectively the list of fully qualified
column
/// This function returns effectively the list of fully qualified
item
/// names, that is category_name + '.' +
column_name for each column
/// names, that is category_name + '.' +
item_name for each item
std
::
vector
<
std
::
string
>
get_tag_order
()
const
;
std
::
vector
<
std
::
string
>
get_tag_order
()
const
;
/// Write the contents of the category to the std::ostream @a os
/// Write the contents of the category to the std::ostream @a os
void
write
(
std
::
ostream
&
os
)
const
;
void
write
(
std
::
ostream
&
os
)
const
;
/// @brief Write the contents of the category to the std::ostream @a os and
/// @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
/// use @a order as the order of the
items. If @a addMissingItem
s is
/// false,
column
s that do not contain any value will be suppressed
/// false,
item
s that do not contain any value will be suppressed
/// @param os The std::ostream to write to
/// @param os The std::ostream to write to
/// @param order The order in which the
column
s should appear
/// @param order The order in which the
item
s should appear
/// @param addMissing
Columns When false, empty column
s are suppressed from the output
/// @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
Column
s
=
true
);
void
write
(
std
::
ostream
&
os
,
const
std
::
vector
<
std
::
string
>
&
order
,
bool
addMissing
Item
s
=
true
);
private
:
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
:
public
:
/// friend function to make it possible to do:
/// friend function to make it possible to do:
...
@@ -1099,7 +1168,7 @@ class category
...
@@ -1099,7 +1168,7 @@ class category
}
}
private
:
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
);
void
erase_orphans
(
condition
&&
cond
,
category
&
parent
);
...
@@ -1136,12 +1205,12 @@ class category
...
@@ -1136,12 +1205,12 @@ class category
row_handle
create_copy
(
row_handle
r
);
row_handle
create_copy
(
row_handle
r
);
struct
item_
column
struct
item_
entry
{
{
std
::
string
m_name
;
std
::
string
m_name
;
const
item_validator
*
m_validator
;
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_name
(
name
)
,
m_validator
(
validator
)
,
m_validator
(
validator
)
{
{
...
@@ -1171,12 +1240,12 @@ class category
...
@@ -1171,12 +1240,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
::
string
m_name
;
std
::
vector
<
item_
column
>
m_column
s
;
std
::
vector
<
item_
entry
>
m_item
s
;
const
validator
*
m_validator
=
nullptr
;
const
validator
*
m_validator
=
nullptr
;
const
category_validator
*
m_cat_validator
=
nullptr
;
const
category_validator
*
m_cat_validator
=
nullptr
;
std
::
vector
<
link
>
m_parent_links
,
m_child_links
;
std
::
vector
<
link
>
m_parent_links
,
m_child_links
;
...
...
include/cif++/condition.hpp
View file @
2792caec
...
@@ -39,17 +39,17 @@
...
@@ -39,17 +39,17 @@
* query you can use to find rows in a @ref cif::category
* query you can use to find rows in a @ref cif::category
*
*
* Conditions are created as standard C++ expressions. That means
* 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
* contents with a value and boolean operators to chain everything
* together.
* 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}
* @code {.cpp}
* cif::condition c = cif::key("id") == 1;
* cif::condition c = cif::key("id") == 1;
* @endcode
* @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:
* using cif::key is a bit too much typing, you can also write:
*
*
* @code{.cpp}
* @code{.cpp}
...
@@ -64,7 +64,7 @@
...
@@ -64,7 +64,7 @@
* auto c3 = "id"_key == 1 or "id"_key == 2;
* auto c3 = "id"_key == 1 or "id"_key == 2;
* @endcode
* @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:
* do not have a value:
*
*
* @code{.cpp}
* @code{.cpp}
...
@@ -83,7 +83,7 @@
...
@@ -83,7 +83,7 @@
* auto c6 = cif::all;
* auto c6 = cif::all;
* @endcode
* @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}
* @code{.cpp}
* auto c7 = cif::any == "foo";
* auto c7 = cif::any == "foo";
...
@@ -104,31 +104,40 @@ namespace cif
...
@@ -104,31 +104,40 @@ namespace cif
/// we declare a function to access its contents
/// 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
* @param cat The category whose
item
s to return
* @return iset The set of key
field
names
* @return iset The set of key
item
names
*/
*/
[[
deprecated
(
"use get_category_items instead"
)]]
iset
get_category_fields
(
const
category
&
cat
);
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 cat The category
* @param col The name of the
column
* @param col The name of the
item
* @return uint16_t The index
* @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 cat The category
* @param col The
column
name
* @param col The
item
name
* @return true If the primitive type is of type *uchar*
* @return true If the primitive type is of type *uchar*
* @return false If the primitive type is not 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
// some more templates to be able to do querying
...
@@ -219,7 +228,7 @@ class condition
...
@@ -219,7 +228,7 @@ class condition
/**
/**
* @brief Prepare the condition to be used on category @a c. This will
* @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
* @param c The category this query should act upon
*/
*/
...
@@ -312,7 +321,7 @@ namespace detail
...
@@ -312,7 +321,7 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
condition_impl
*
prepare
(
const
category
&
c
)
override
{
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
return
this
;
return
this
;
}
}
...
@@ -339,7 +348,7 @@ namespace detail
...
@@ -339,7 +348,7 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
condition_impl
*
prepare
(
const
category
&
c
)
override
{
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
return
this
;
return
this
;
}
}
...
@@ -415,8 +424,8 @@ namespace detail
...
@@ -415,8 +424,8 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
condition_impl
*
prepare
(
const
category
&
c
)
override
{
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
m_icase
=
is_
column
_type_uchar
(
c
,
m_item_tag
);
m_icase
=
is_
item
_type_uchar
(
c
,
m_item_tag
);
return
this
;
return
this
;
}
}
...
@@ -473,8 +482,8 @@ namespace detail
...
@@ -473,8 +482,8 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
condition_impl
*
prepare
(
const
category
&
c
)
override
{
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
m_icase
=
is_
column
_type_uchar
(
c
,
m_item_tag
);
m_icase
=
is_
item
_type_uchar
(
c
,
m_item_tag
);
return
this
;
return
this
;
}
}
...
@@ -506,7 +515,7 @@ namespace detail
...
@@ -506,7 +515,7 @@ namespace detail
condition_impl
*
prepare
(
const
category
&
c
)
override
condition_impl
*
prepare
(
const
category
&
c
)
override
{
{
m_item_ix
=
get_
column
_ix
(
c
,
m_item_tag
);
m_item_ix
=
get_
item
_ix
(
c
,
m_item_tag
);
return
this
;
return
this
;
}
}
...
@@ -541,7 +550,7 @@ namespace detail
...
@@ -541,7 +550,7 @@ namespace detail
auto
&
c
=
r
.
get_category
();
auto
&
c
=
r
.
get_category
();
bool
result
=
false
;
bool
result
=
false
;
for
(
auto
&
f
:
get_category_
field
s
(
c
))
for
(
auto
&
f
:
get_category_
item
s
(
c
))
{
{
try
try
{
{
...
@@ -579,7 +588,7 @@ namespace detail
...
@@ -579,7 +588,7 @@ namespace detail
auto
&
c
=
r
.
get_category
();
auto
&
c
=
r
.
get_category
();
bool
result
=
false
;
bool
result
=
false
;
for
(
auto
&
f
:
get_category_
field
s
(
c
))
for
(
auto
&
f
:
get_category_
item
s
(
c
))
{
{
try
try
{
{
...
@@ -887,7 +896,7 @@ inline condition operator or(condition &&a, condition &&b)
...
@@ -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}
* @code{.cpp}
* "id"_key == cif::empty_type();
* "id"_key == cif::empty_type();
...
@@ -909,7 +918,7 @@ struct empty_type
...
@@ -909,7 +918,7 @@ struct empty_type
inline
constexpr
empty_type
null
=
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
struct
key
...
@@ -947,7 +956,7 @@ struct key
...
@@ -947,7 +956,7 @@ struct key
key
(
const
key
&
)
=
delete
;
key
(
const
key
&
)
=
delete
;
key
&
operator
=
(
const
key
&
)
=
delete
;
key
&
operator
=
(
const
key
&
)
=
delete
;
std
::
string
m_item_tag
;
///< The
column
name
std
::
string
m_item_tag
;
///< The
item
name
};
};
/**
/**
...
@@ -1072,7 +1081,7 @@ inline condition operator!=(const key &key, const empty_type &)
...
@@ -1072,7 +1081,7 @@ inline condition operator!=(const key &key, const empty_type &)
}
}
/**
/**
* @brief Create a condition to search any
column
for a value @a v if @a v contains a value
* @brief Create a condition to search any
item
for a value @a v if @a v contains a value
* compare to null if not.
* compare to null if not.
*/
*/
template
<
typename
T
>
template
<
typename
T
>
...
@@ -1099,12 +1108,12 @@ struct any_type
...
@@ -1099,12 +1108,12 @@ struct any_type
/** @endcond */
/** @endcond */
/**
/**
* @brief A helper for any
field
constructs
* @brief A helper for any
item
constructs
*/
*/
inline
constexpr
any_type
any
=
any_type
{};
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
>
template
<
typename
T
>
condition
operator
==
(
const
any_type
&
,
const
T
&
v
)
condition
operator
==
(
const
any_type
&
,
const
T
&
v
)
...
@@ -1113,7 +1122,7 @@ 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
)
inline
condition
operator
==
(
const
any_type
&
,
const
std
::
regex
&
rx
)
{
{
...
@@ -1131,9 +1140,9 @@ inline condition all()
...
@@ -1131,9 +1140,9 @@ inline condition all()
namespace
literals
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
* @param length The length of @a text
* @return key The cif::key created
* @return key The cif::key created
*/
*/
...
...
include/cif++/item.hpp
View file @
2792caec
...
@@ -44,7 +44,7 @@
...
@@ -44,7 +44,7 @@
/** \file item.hpp
/** \file item.hpp
*
*
* This file contains the declaration of item but also the item_value and item_handle
* 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
namespace
cif
...
@@ -227,10 +227,10 @@ class item
...
@@ -227,10 +227,10 @@ class item
/// \brief empty means either null or unknown
/// \brief empty means either null or unknown
bool
empty
()
const
{
return
m_value
.
empty
();
}
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
==
"."
;
}
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
==
"?"
;
}
bool
is_unknown
()
const
{
return
m_value
==
"?"
;
}
/// \brief the length of the value string
/// \brief the length of the value string
...
@@ -464,14 +464,14 @@ struct item_handle
...
@@ -464,14 +464,14 @@ struct item_handle
/** Easy way to test for an empty item */
/** Easy way to test for an empty item */
explicit
operator
bool
()
const
{
return
not
empty
();
}
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
bool
is_null
()
const
{
{
auto
txt
=
text
();
auto
txt
=
text
();
return
txt
.
length
()
==
1
and
txt
.
front
()
==
'.'
;
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
bool
is_unknown
()
const
{
{
auto
txt
=
text
();
auto
txt
=
text
();
...
@@ -484,11 +484,11 @@ struct item_handle
...
@@ -484,11 +484,11 @@ struct item_handle
/**
/**
* @brief Construct a new item handle object
* @brief Construct a new item handle object
*
*
* @param
column Column
index
* @param
item Item
index
* @param row Reference to the row
* @param row Reference to the row
*/
*/
item_handle
(
uint16_t
column
,
row_handle
&
row
)
item_handle
(
uint16_t
item
,
row_handle
&
row
)
:
m_
column
(
column
)
:
m_
item_ix
(
item
)
,
m_row_handle
(
row
)
,
m_row_handle
(
row
)
{
{
}
}
...
@@ -505,7 +505,7 @@ struct item_handle
...
@@ -505,7 +505,7 @@ struct item_handle
private
:
private
:
item_handle
();
item_handle
();
uint16_t
m_
column
;
uint16_t
m_
item_ix
;
row_handle
&
m_row_handle
;
row_handle
&
m_row_handle
;
void
assign_value
(
const
item
&
value
);
void
assign_value
(
const
item
&
value
);
...
...
include/cif++/iterator.hpp
View file @
2792caec
...
@@ -90,7 +90,7 @@ class iterator_impl
...
@@ -90,7 +90,7 @@ class iterator_impl
:
m_category
(
rhs
.
m_category
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_current
(
rhs
.
m_current
)
,
m_value
(
rhs
.
m_value
)
,
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
...
@@ -99,7 +99,7 @@ class iterator_impl
:
m_category
(
rhs
.
m_category
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
const_cast
<
row_type
*>
(
rhs
.
m_current
))
,
m_current
(
const_cast
<
row_type
*>
(
rhs
.
m_current
))
,
m_value
(
rhs
.
m_value
)
,
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
>
());
m_value
=
get
(
std
::
make_index_sequence
<
N
>
());
}
}
...
@@ -108,7 +108,7 @@ class iterator_impl
...
@@ -108,7 +108,7 @@ class iterator_impl
iterator_impl
(
const
iterator_impl
<
IRowType
>
&
rhs
,
const
std
::
array
<
uint16_t
,
N
>
&
cix
)
iterator_impl
(
const
iterator_impl
<
IRowType
>
&
rhs
,
const
std
::
array
<
uint16_t
,
N
>
&
cix
)
:
m_category
(
rhs
.
m_category
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_current
(
rhs
.
m_current
)
,
m_
column
_ix
(
cix
)
,
m_
item
_ix
(
cix
)
{
{
m_value
=
get
(
std
::
make_index_sequence
<
N
>
());
m_value
=
get
(
std
::
make_index_sequence
<
N
>
());
}
}
...
@@ -117,7 +117,7 @@ class iterator_impl
...
@@ -117,7 +117,7 @@ class iterator_impl
{
{
m_category
=
i
.
m_category
;
m_category
=
i
.
m_category
;
m_current
=
i
.
m_current
;
m_current
=
i
.
m_current
;
m_
column_ix
=
i
.
m_column
_ix
;
m_
item_ix
=
i
.
m_item
_ix
;
m_value
=
i
.
m_value
;
m_value
=
i
.
m_value
;
return
*
this
;
return
*
this
;
}
}
...
@@ -185,7 +185,7 @@ class iterator_impl
...
@@ -185,7 +185,7 @@ class iterator_impl
if
(
m_current
!=
nullptr
)
if
(
m_current
!=
nullptr
)
{
{
row_handle
rh
{
*
m_category
,
*
m_current
};
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
{};
return
{};
...
@@ -194,7 +194,7 @@ class iterator_impl
...
@@ -194,7 +194,7 @@ class iterator_impl
category_type
*
m_category
=
nullptr
;
category_type
*
m_category
=
nullptr
;
row_type
*
m_current
=
nullptr
;
row_type
*
m_current
=
nullptr
;
value_type
m_value
;
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>
...
@@ -348,7 +348,7 @@ class iterator_impl<Category, T>
:
m_category
(
rhs
.
m_category
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_current
(
rhs
.
m_current
)
,
m_value
(
rhs
.
m_value
)
,
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>
...
@@ -357,7 +357,7 @@ class iterator_impl<Category, T>
:
m_category
(
rhs
.
m_category
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
const_cast
<
row_type
*>
(
rhs
.
m_current
))
,
m_current
(
const_cast
<
row_type
*>
(
rhs
.
m_current
))
,
m_value
(
rhs
.
m_value
)
,
m_value
(
rhs
.
m_value
)
,
m_
column_ix
(
rhs
.
m_column
_ix
)
,
m_
item_ix
(
rhs
.
m_item
_ix
)
{
{
m_value
=
get
(
m_current
);
m_value
=
get
(
m_current
);
}
}
...
@@ -366,7 +366,7 @@ class iterator_impl<Category, T>
...
@@ -366,7 +366,7 @@ class iterator_impl<Category, T>
iterator_impl
(
const
iterator_impl
<
IRowType
>
&
rhs
,
const
std
::
array
<
uint16_t
,
1
>
&
cix
)
iterator_impl
(
const
iterator_impl
<
IRowType
>
&
rhs
,
const
std
::
array
<
uint16_t
,
1
>
&
cix
)
:
m_category
(
rhs
.
m_category
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_current
(
rhs
.
m_current
)
,
m_
column
_ix
(
cix
[
0
])
,
m_
item
_ix
(
cix
[
0
])
{
{
m_value
=
get
();
m_value
=
get
();
}
}
...
@@ -375,7 +375,7 @@ class iterator_impl<Category, T>
...
@@ -375,7 +375,7 @@ class iterator_impl<Category, T>
{
{
m_category
=
i
.
m_category
;
m_category
=
i
.
m_category
;
m_current
=
i
.
m_current
;
m_current
=
i
.
m_current
;
m_
column_ix
=
i
.
m_column
_ix
;
m_
item_ix
=
i
.
m_item
_ix
;
m_value
=
i
.
m_value
;
m_value
=
i
.
m_value
;
return
*
this
;
return
*
this
;
}
}
...
@@ -442,7 +442,7 @@ class iterator_impl<Category, T>
...
@@ -442,7 +442,7 @@ class iterator_impl<Category, T>
if
(
m_current
!=
nullptr
)
if
(
m_current
!=
nullptr
)
{
{
row_handle
rh
{
*
m_category
,
*
m_current
};
row_handle
rh
{
*
m_category
,
*
m_current
};
return
rh
[
m_
column
_ix
].
template
as
<
T
>
();
return
rh
[
m_
item
_ix
].
template
as
<
T
>
();
}
}
return
{};
return
{};
...
@@ -451,7 +451,7 @@ class iterator_impl<Category, T>
...
@@ -451,7 +451,7 @@ class iterator_impl<Category, T>
category_type
*
m_category
=
nullptr
;
category_type
*
m_category
=
nullptr
;
row_type
*
m_current
=
nullptr
;
row_type
*
m_current
=
nullptr
;
value_type
m_value
;
value_type
m_value
;
uint16_t
m_
column
_ix
;
uint16_t
m_
item
_ix
;
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -482,8 +482,8 @@ class iterator_proxy
...
@@ -482,8 +482,8 @@ class iterator_proxy
using
iterator
=
iterator_impl
<
category_type
,
Ts
...
>
;
using
iterator
=
iterator_impl
<
category_type
,
Ts
...
>
;
using
row_iterator
=
iterator_impl
<
category_type
>
;
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
,
char
const
*
const
item
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
,
std
::
initializer_list
<
char
const
*>
item
s
);
iterator_proxy
(
iterator_proxy
&&
p
);
iterator_proxy
(
iterator_proxy
&&
p
);
iterator_proxy
&
operator
=
(
iterator_proxy
&&
p
);
iterator_proxy
&
operator
=
(
iterator_proxy
&&
p
);
...
@@ -492,8 +492,8 @@ class iterator_proxy
...
@@ -492,8 +492,8 @@ class iterator_proxy
iterator_proxy
&
operator
=
(
const
iterator_proxy
&
)
=
delete
;
iterator_proxy
&
operator
=
(
const
iterator_proxy
&
)
=
delete
;
/** @endcond */
/** @endcond */
iterator
begin
()
const
{
return
iterator
(
m_begin
,
m_
column
_ix
);
}
///< Return the iterator pointing to the first 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_
column
_ix
);
}
///< Return the iterator pointing past the last 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
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
explicit
operator
bool
()
const
{
return
not
empty
();
}
///< Easy way to detect if the range is empty
...
@@ -510,13 +510,13 @@ class iterator_proxy
...
@@ -510,13 +510,13 @@ class iterator_proxy
std
::
swap
(
m_category
,
rhs
.
m_category
);
std
::
swap
(
m_category
,
rhs
.
m_category
);
std
::
swap
(
m_begin
,
rhs
.
m_begin
);
std
::
swap
(
m_begin
,
rhs
.
m_begin
);
std
::
swap
(
m_end
,
rhs
.
m_end
);
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
:
private
:
category_type
*
m_category
;
category_type
*
m_category
;
row_iterator
m_begin
,
m_end
;
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
...
@@ -651,26 +651,26 @@ class conditional_iterator_proxy
/** @cond */
/** @cond */
template
<
typename
Category
,
typename
...
Ts
>
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_category
(
&
cat
)
,
m_begin
(
pos
)
,
m_begin
(
pos
)
,
m_end
(
cat
.
end
())
,
m_end
(
cat
.
end
())
{
{
for
(
uint16_t
i
=
0
;
i
<
N
;
++
i
)
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
>
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_category
(
&
cat
)
,
m_begin
(
pos
)
,
m_begin
(
pos
)
,
m_end
(
cat
.
end
())
,
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
;
std
::
uint16_t
i
=
0
;
for
(
auto
column
:
column
s
)
for
(
auto
item
:
item
s
)
m_
column_ix
[
i
++
]
=
m_category
->
get_column_ix
(
column
);
m_
item_ix
[
i
++
]
=
m_category
->
get_item_ix
(
item
);
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -707,7 +707,7 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
...
@@ -707,7 +707,7 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
,
mCBegin
(
pos
)
,
mCBegin
(
pos
)
,
mCEnd
(
cat
.
end
())
,
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
)
if
(
m_condition
)
{
{
...
@@ -720,7 +720,7 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
...
@@ -720,7 +720,7 @@ conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category
mCBegin
=
mCEnd
;
mCBegin
=
mCEnd
;
uint16_t
i
=
0
;
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
>
template
<
typename
Category
,
typename
...
Ts
>
...
...
include/cif++/model.hpp
View file @
2792caec
...
@@ -72,7 +72,7 @@ class structure;
...
@@ -72,7 +72,7 @@ class structure;
*
*
* The class atom is a kind of flyweight class. It can be copied
* The class atom is a kind of flyweight class. It can be copied
* with low overhead. All data is stored in the underlying mmCIF
* 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.
* impl.
*
*
* It is also possible to have symmetry copies of atoms. They
* It is also possible to have symmetry copies of atoms. They
...
@@ -207,7 +207,7 @@ class atom
...
@@ -207,7 +207,7 @@ class atom
/// \brief Copy assignement operator
/// \brief Copy assignement operator
atom
&
operator
=
(
const
atom
&
rhs
)
=
default
;
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
std
::
string
get_property
(
std
::
string_view
name
)
const
{
{
if
(
not
m_impl
)
if
(
not
m_impl
)
...
@@ -215,7 +215,7 @@ class atom
...
@@ -215,7 +215,7 @@ class atom
return
m_impl
->
get_property
(
name
);
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
int
get_property_int
(
std
::
string_view
name
)
const
{
{
if
(
not
m_impl
)
if
(
not
m_impl
)
...
@@ -223,7 +223,7 @@ class atom
...
@@ -223,7 +223,7 @@ class atom
return
m_impl
->
get_property_int
(
name
);
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
float
get_property_float
(
std
::
string_view
name
)
const
{
{
if
(
not
m_impl
)
if
(
not
m_impl
)
...
@@ -231,7 +231,7 @@ class atom
...
@@ -231,7 +231,7 @@ class atom
return
m_impl
->
get_property_float
(
name
);
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
)
void
set_property
(
const
std
::
string_view
name
,
const
std
::
string
&
value
)
{
{
if
(
not
m_impl
)
if
(
not
m_impl
)
...
@@ -239,7 +239,7 @@ class atom
...
@@ -239,7 +239,7 @@ class atom
m_impl
->
set_property
(
name
,
value
);
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
>
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
)
void
set_property
(
const
std
::
string_view
name
,
const
T
&
value
)
{
{
...
@@ -730,7 +730,7 @@ class sugar : public residue
...
@@ -730,7 +730,7 @@ class sugar : public residue
/**
/**
* @brief Return the sugar number in the glycosylation tree
* @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
* 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
* and auth_seq_id is specified to contain a string, we do a check here
* to see if it really is a number.
* to see if it really is a number.
...
...
include/cif++/parser.hpp
View file @
2792caec
...
@@ -268,8 +268,8 @@ class sac_parser
...
@@ -268,8 +268,8 @@ class sac_parser
QuotedStringQuote
,
QuotedStringQuote
,
UnquotedString
,
UnquotedString
,
Tag
,
Tag
,
Text
Field
,
Text
Item
,
Text
Field
NL
,
Text
Item
NL
,
Reserved
,
Reserved
,
Value
Value
};
};
...
...
include/cif++/pdb.hpp
View file @
2792caec
...
@@ -28,6 +28,8 @@
...
@@ -28,6 +28,8 @@
#include "cif++/file.hpp"
#include "cif++/file.hpp"
#include <system_error>
/**
/**
* @file pdb.hpp
* @file pdb.hpp
*
*
...
@@ -120,6 +122,8 @@ void reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx
...
@@ -120,6 +122,8 @@ void reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx
*
*
* Use the common \ref cif::VERBOSE flag to turn on diagnostic messages.
* 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 file The input file
* \param dictionary The mmcif dictionary to use
* \param dictionary The mmcif dictionary to use
* \result Returns true if the file was valid and consistent
* \result Returns true if the file was valid and consistent
...
@@ -127,6 +131,43 @@ void reconstruct_pdbx(file &pdbx_file, std::string_view dictionary = "mmcif_pdbx
...
@@ -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"
);
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
// Other I/O related routines
...
...
include/cif++/row.hpp
View file @
2792caec
...
@@ -51,7 +51,7 @@
...
@@ -51,7 +51,7 @@
* std::string name = rh["label_atom_id"].as<std::string>();
* std::string name = rh["label_atom_id"].as<std::string>();
*
*
* // by index:
* // 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);
* assert(rh[ix].as<std::string() == name);
* @endcode
* @endcode
*
*
...
@@ -87,15 +87,15 @@ namespace detail
...
@@ -87,15 +87,15 @@ namespace detail
{
{
static
constexpr
size_t
N
=
sizeof
...(
C
);
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_row
(
r
)
,
m_
columns
(
std
::
move
(
column
s
))
,
m_
items
(
std
::
move
(
item
s
))
{
{
}
}
const
item_handle
operator
[](
uint16_t
ix
)
const
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
>
template
<
typename
...
Ts
,
std
::
enable_if_t
<
N
==
sizeof
...(
Ts
),
int
>
=
0
>
...
@@ -107,11 +107,11 @@ namespace detail
...
@@ -107,11 +107,11 @@ namespace detail
template
<
typename
...
Ts
,
size_t
...
Is
>
template
<
typename
...
Ts
,
size_t
...
Is
>
std
::
tuple
<
Ts
...
>
get
(
std
::
index_sequence
<
Is
...
>
)
const
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
;
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
// 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
...
@@ -244,70 +244,70 @@ class row_handle
return
not
empty
();
return
not
empty
();
}
}
/// \brief return a cif::item_handle to the item in
column @a column
_ix
/// \brief return a cif::item_handle to the item in
item @a item
_ix
item_handle
operator
[](
uint16_t
column
_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
/// \brief return a const cif::item_handle to the item in
item @a item
_ix
const
item_handle
operator
[](
uint16_t
column
_ix
)
const
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
/// \brief return a cif::item_handle to the item in the
item named @a item
_name
item_handle
operator
[](
std
::
string_view
column
_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
/// \brief return a const cif::item_handle to the item in the
item named @a item
_name
const
item_handle
operator
[](
std
::
string_view
column
_name
)
const
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
/// \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
>
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
>
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
>
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
>
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
)
void
assign
(
const
std
::
vector
<
item
>
&
values
)
{
{
for
(
auto
&
value
:
values
)
for
(
auto
&
value
:
values
)
assign
(
value
,
true
);
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.
* 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
* and the link results in a linked record in another category
* this record in the linked category is updated as well.
* this record in the linked category is updated as well.
*
*
...
@@ -317,13 +317,13 @@ class row_handle
...
@@ -317,13 +317,13 @@ class row_handle
void
assign
(
std
::
string_view
name
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
)
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.
* 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
* and the link results in a linked record in another category
* this record in the linked category is updated as well.
* this record in the linked category is updated as well.
*
*
...
@@ -331,7 +331,7 @@ class row_handle
...
@@ -331,7 +331,7 @@ class row_handle
* checked to see if it conforms to the rules defined in the dictionary
* 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
/// \brief compare two rows
bool
operator
==
(
const
row_handle
&
rhs
)
const
{
return
m_category
==
rhs
.
m_category
and
m_row
==
rhs
.
m_row
;
}
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
...
@@ -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
;
}
bool
operator
!=
(
const
row_handle
&
rhs
)
const
{
return
m_category
!=
rhs
.
m_category
or
m_row
!=
rhs
.
m_row
;
}
private
:
private
:
uint16_t
get_
column
_ix
(
std
::
string_view
name
)
const
;
uint16_t
get_
item
_ix
(
std
::
string_view
name
)
const
;
std
::
string_view
get_
column
_name
(
uint16_t
ix
)
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
()
row
*
get_row
()
{
{
...
@@ -360,7 +360,7 @@ class row_handle
...
@@ -360,7 +360,7 @@ class row_handle
assign
(
i
.
name
(),
i
.
value
(),
updateLinked
);
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
;
category
*
m_category
=
nullptr
;
row
*
m_row
=
nullptr
;
row
*
m_row
=
nullptr
;
...
...
include/cif++/validate.hpp
View file @
2792caec
...
@@ -28,9 +28,11 @@
...
@@ -28,9 +28,11 @@
#include "cif++/text.hpp"
#include "cif++/text.hpp"
#include <cassert>
#include <filesystem>
#include <filesystem>
#include <list>
#include <list>
#include <mutex>
#include <mutex>
#include <system_error>
#include <utility>
#include <utility>
/**
/**
...
@@ -49,29 +51,123 @@ namespace cif
...
@@ -49,29 +51,123 @@ namespace cif
struct
category_validator
;
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
:
public
:
/// @brief Constructor
/**
validation_error
(
const
std
::
string
&
msg
);
* @brief User friendly name
*
* @return const char*
*/
/// @brief Constructor
const
char
*
name
()
const
noexcept
override
validation_error
(
const
std
::
string
&
cat
,
const
std
::
string
&
item
,
{
const
std
::
string
&
msg
);
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"
;
}
}
/**
* @brief Return whether two error codes are equivalent, always false in this case
*
*/
/// @cond
bool
equivalent
(
const
std
::
error_code
&
/*code*/
,
int
/*condition*/
)
const
noexcept
override
std
::
string
m_msg
;
{
/// @endcond
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 */
/** @brief the primitive types known */
...
@@ -85,6 +181,9 @@ enum class DDL_PrimitiveType
...
@@ -85,6 +181,9 @@ enum class DDL_PrimitiveType
/// @brief Return the DDL_PrimitiveType encoded in @a s
/// @brief Return the DDL_PrimitiveType encoded in @a s
DDL_PrimitiveType
map_to_primitive_type
(
std
::
string_view
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
;
struct
regex_impl
;
/**
/**
...
@@ -188,8 +287,11 @@ struct item_validator
...
@@ -188,8 +287,11 @@ struct item_validator
}
}
/// @brief Validate the value in @a value for this item
/// @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
;
void
operator
()(
std
::
string_view
value
)
const
;
/// @brief A more gentle version of value validation
bool
validate_value
(
std
::
string_view
value
,
std
::
error_code
&
ec
)
const
noexcept
;
};
};
/**
/**
...
@@ -203,7 +305,7 @@ struct category_validator
...
@@ -203,7 +305,7 @@ struct category_validator
std
::
string
m_name
;
///< The name of the category
std
::
string
m_name
;
///< The name of the category
std
::
vector
<
std
::
string
>
m_keys
;
///< The list of items that make up the key
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_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
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
/// @brief return true if this category sorts before @a rhs
...
@@ -298,7 +400,24 @@ class validator
...
@@ -298,7 +400,24 @@ class validator
std
::
vector
<
const
link_validator
*>
get_links_for_child
(
std
::
string_view
category
)
const
;
std
::
vector
<
const
link_validator
*>
get_links_for_child
(
std
::
string_view
category
)
const
;
/// @brief Bottleneck function to report an error in validation
/// @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
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
void
set_name
(
const
std
::
string
&
name
)
{
m_name
=
name
;
}
///< Set the name of this validator
...
...
src/category.cpp
View file @
2792caec
...
@@ -33,7 +33,7 @@
...
@@ -33,7 +33,7 @@
#include <stack>
#include <stack>
// TODO: Find out what the rules are exactly for linked items, the current implementation
// 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.
// set of linked items is null at one side and not null in the other.
namespace
cif
namespace
cif
...
@@ -52,7 +52,7 @@ class row_comparator
...
@@ -52,7 +52,7 @@ class row_comparator
for
(
auto
&
k
:
cv
->
m_keys
)
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
);
auto
iv
=
cv
->
get_validator_for_item
(
k
);
if
(
iv
==
nullptr
)
if
(
iv
==
nullptr
)
...
@@ -300,7 +300,7 @@ class category_index
...
@@ -300,7 +300,7 @@ class category_index
return
h
;
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
)
entry
*
reorder
(
entry
*
e
)
{
{
auto
result
=
e
;
auto
result
=
e
;
...
@@ -356,9 +356,9 @@ row *category_index::find_by_value(const category &cat, row_initializer k) const
...
@@ -356,9 +356,9 @@ row *category_index::find_by_value(const category &cat, row_initializer k) const
// sort the values in k first
// sort the values in k first
row_initializer
k2
;
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
)
auto
ki
=
find_if
(
k
.
begin
(),
k
.
end
(),
[
&
fld
](
auto
&
i
)
{
return
i
.
name
()
==
fld
;
});
{
return
i
.
name
()
==
fld
;
});
...
@@ -404,7 +404,7 @@ category_index::entry *category_index::insert(category &cat, entry *h, row *v)
...
@@ -404,7 +404,7 @@ category_index::entry *category_index::insert(category &cat, entry *h, row *v)
row_handle
rh
(
cat
,
*
v
);
row_handle
rh
(
cat
,
*
v
);
std
::
ostringstream
os
;
std
::
ostringstream
os
;
for
(
auto
col
:
cat
.
key_
field
s
())
for
(
auto
col
:
cat
.
key_
item
s
())
{
{
if
(
rh
[
col
])
if
(
rh
[
col
])
os
<<
col
<<
": "
<<
std
::
quoted
(
rh
[
col
].
text
())
<<
"; "
;
os
<<
col
<<
": "
<<
std
::
quoted
(
rh
[
col
].
text
())
<<
"; "
;
...
@@ -508,7 +508,7 @@ category::category(std::string_view name)
...
@@ -508,7 +508,7 @@ category::category(std::string_view name)
category
::
category
(
const
category
&
rhs
)
category
::
category
(
const
category
&
rhs
)
:
m_name
(
rhs
.
m_name
)
:
m_name
(
rhs
.
m_name
)
,
m_
columns
(
rhs
.
m_column
s
)
,
m_
items
(
rhs
.
m_item
s
)
,
m_cascade
(
rhs
.
m_cascade
)
,
m_cascade
(
rhs
.
m_cascade
)
{
{
for
(
auto
r
=
rhs
.
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
for
(
auto
r
=
rhs
.
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
...
@@ -523,7 +523,7 @@ category::category(const category &rhs)
...
@@ -523,7 +523,7 @@ category::category(const category &rhs)
category
::
category
(
category
&&
rhs
)
category
::
category
(
category
&&
rhs
)
:
m_name
(
std
::
move
(
rhs
.
m_name
))
:
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_validator
(
rhs
.
m_validator
)
,
m_cat_validator
(
rhs
.
m_cat_validator
)
,
m_cat_validator
(
rhs
.
m_cat_validator
)
,
m_parent_links
(
std
::
move
(
rhs
.
m_parent_links
))
,
m_parent_links
(
std
::
move
(
rhs
.
m_parent_links
))
...
@@ -546,7 +546,7 @@ category &category::operator=(const category &rhs)
...
@@ -546,7 +546,7 @@ category &category::operator=(const category &rhs)
clear
();
clear
();
m_name
=
rhs
.
m_name
;
m_name
=
rhs
.
m_name
;
m_
columns
=
rhs
.
m_column
s
;
m_
items
=
rhs
.
m_item
s
;
m_cascade
=
rhs
.
m_cascade
;
m_cascade
=
rhs
.
m_cascade
;
m_validator
=
nullptr
;
m_validator
=
nullptr
;
...
@@ -573,7 +573,7 @@ category &category::operator=(category &&rhs)
...
@@ -573,7 +573,7 @@ category &category::operator=(category &&rhs)
if
(
this
!=
&
rhs
)
if
(
this
!=
&
rhs
)
{
{
m_name
=
std
::
move
(
rhs
.
m_name
);
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_cascade
=
rhs
.
m_cascade
;
m_validator
=
rhs
.
m_validator
;
m_validator
=
rhs
.
m_validator
;
m_cat_validator
=
rhs
.
m_cat_validator
;
m_cat_validator
=
rhs
.
m_cat_validator
;
...
@@ -595,11 +595,11 @@ category::~category()
...
@@ -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
;
continue
;
for
(
row
*
r
=
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
for
(
row
*
r
=
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
...
@@ -608,43 +608,43 @@ void category::remove_column(std::string_view column_name)
...
@@ -608,43 +608,43 @@ void category::remove_column(std::string_view column_name)
r
->
erase
(
r
->
begin
()
+
ix
);
r
->
erase
(
r
->
begin
()
+
ix
);
}
}
m_
columns
.
erase
(
m_column
s
.
begin
()
+
ix
);
m_
items
.
erase
(
m_item
s
.
begin
()
+
ix
);
break
;
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
;
continue
;
m_
column
s
[
ix
].
m_name
=
to_name
;
m_
item
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_validator
=
m_cat_validator
?
m_cat_validator
->
get_validator_for_item
(
to_name
)
:
nullptr
;
break
;
break
;
}
}
}
}
iset
category
::
get_
column
s
()
const
iset
category
::
get_
item
s
()
const
{
{
iset
result
;
iset
result
;
for
(
auto
&
col
:
m_
column
s
)
for
(
auto
&
col
:
m_
item
s
)
result
.
insert
(
col
.
m_name
);
result
.
insert
(
col
.
m_name
);
return
result
;
return
result
;
}
}
iset
category
::
key_
field
s
()
const
iset
category
::
key_
item
s
()
const
{
{
if
(
m_validator
==
nullptr
)
if
(
m_validator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
m_cat_validator
==
nullptr
)
if
(
m_cat_validator
==
nullptr
)
m_validator
->
report_error
(
"undefined Category"
,
true
);
m_validator
->
report_error
(
validation_error
::
undefined_category
);
iset
result
;
iset
result
;
for
(
auto
&
iv
:
m_cat_validator
->
m_item_validators
)
for
(
auto
&
iv
:
m_cat_validator
->
m_item_validators
)
...
@@ -653,17 +653,17 @@ iset category::key_fields() const
...
@@ -653,17 +653,17 @@ iset category::key_fields() const
return
result
;
return
result
;
}
}
std
::
set
<
uint16_t
>
category
::
key_
field
_indices
()
const
std
::
set
<
uint16_t
>
category
::
key_
item
_indices
()
const
{
{
if
(
m_validator
==
nullptr
)
if
(
m_validator
==
nullptr
)
throw
std
::
runtime_error
(
"No Validator specified"
);
throw
std
::
runtime_error
(
"No Validator specified"
);
if
(
m_cat_validator
==
nullptr
)
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
;
std
::
set
<
uint16_t
>
result
;
for
(
auto
&
k
:
m_cat_validator
->
m_keys
)
for
(
auto
&
k
:
m_cat_validator
->
m_keys
)
result
.
insert
(
get_
column
_ix
(
k
));
result
.
insert
(
get_
item
_ix
(
k
));
return
result
;
return
result
;
}
}
...
@@ -693,8 +693,8 @@ void category::set_validator(const validator *v, datablock &db)
...
@@ -693,8 +693,8 @@ void category::set_validator(const validator *v, datablock &db)
std
::
vector
<
uint16_t
>
kix
;
std
::
vector
<
uint16_t
>
kix
;
for
(
auto
k
:
m_cat_validator
->
m_keys
)
for
(
auto
k
:
m_cat_validator
->
m_keys
)
{
{
kix
.
push_back
(
get_
column
_ix
(
k
));
kix
.
push_back
(
get_
item
_ix
(
k
));
if
(
kix
.
back
()
>=
m_
column
s
.
size
())
if
(
kix
.
back
()
>=
m_
item
s
.
size
())
missing
.
insert
(
k
);
missing
.
insert
(
k
);
}
}
}
}
...
@@ -704,7 +704,7 @@ void category::set_validator(const validator *v, datablock &db)
...
@@ -704,7 +704,7 @@ void category::set_validator(const validator *v, datablock &db)
else
else
{
{
std
::
ostringstream
msg
;
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
"
;
<<
cif
::
join
(
missing
,
", "
)
<<
" in "
<<
m_name
<<
" "
<<
(
missing
.
size
()
==
1
?
"is"
:
"are"
)
<<
" missing
\n
"
;
throw
missing_key_error
(
msg
.
str
(),
*
missing
.
begin
());
throw
missing_key_error
(
msg
.
str
(),
*
missing
.
begin
());
}
}
...
@@ -713,8 +713,8 @@ void category::set_validator(const validator *v, datablock &db)
...
@@ -713,8 +713,8 @@ void category::set_validator(const validator *v, datablock &db)
else
else
m_cat_validator
=
nullptr
;
m_cat_validator
=
nullptr
;
for
(
auto
&&
[
column
,
cv
]
:
m_column
s
)
for
(
auto
&&
[
item
,
cv
]
:
m_item
s
)
cv
=
m_cat_validator
?
m_cat_validator
->
get_validator_for_item
(
column
)
:
nullptr
;
cv
=
m_cat_validator
?
m_cat_validator
->
get_validator_for_item
(
item
)
:
nullptr
;
update_links
(
db
);
update_links
(
db
);
}
}
...
@@ -760,31 +760,31 @@ bool category::is_valid() const
...
@@ -760,31 +760,31 @@ bool category::is_valid() const
if
(
m_cat_validator
==
nullptr
)
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
;
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
);
auto
iv
=
m_cat_validator
->
get_validator_for_item
(
col
.
m_name
);
if
(
iv
==
nullptr
)
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
;
result
=
false
;
}
}
// col.m_validator = iv;
// col.m_validator = iv;
if
(
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
);
mandatory
.
erase
(
col
.
m_name
);
}
}
if
(
not
mandatory
.
empty
())
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
;
result
=
false
;
}
}
...
@@ -794,44 +794,44 @@ bool category::is_valid() const
...
@@ -794,44 +794,44 @@ bool category::is_valid() const
for
(
auto
k
:
m_cat_validator
->
m_keys
)
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
);
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
;
result
=
false
;
}
}
#if not defined(NDEBUG)
//
#if not defined(NDEBUG)
// check index?
//
//
check index?
if
(
m_index
)
//
if (m_index)
{
//
{
if
(
m_index
->
size
()
!=
size
())
//
if (m_index->size() != size())
m_validator
->
report_error
(
"size of index is not equal to size of category "
+
m_name
,
true
);
//
m_validator->report_error("size of index is not equal to size of category " + m_name, true);
// m_index->validate();
//
// m_index->validate();
for
(
auto
r
:
*
this
)
//
for (auto r : *this)
{
//
{
auto
p
=
r
.
get_row
();
//
auto p = r.get_row();
if
(
m_index
->
find
(
*
this
,
p
)
!=
p
)
//
if (m_index->find(*this, p) != p)
m_validator
->
report_error
(
"Key not found in index for category "
+
m_name
,
true
);
//
m_validator->report_error("Key not found in index for category " + m_name, true);
}
//
}
}
//
}
#endif
//
#endif
// validate all values
// 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
(
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
;
bool
seen
=
false
;
auto
iv
=
m_
column
s
[
cix
].
m_validator
;
auto
iv
=
m_
item
s
[
cix
].
m_validator
;
if
(
iv
==
nullptr
)
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
;
result
=
false
;
continue
;
continue
;
}
}
...
@@ -840,14 +840,13 @@ bool category::is_valid() const
...
@@ -840,14 +840,13 @@ bool category::is_valid() const
if
(
vi
!=
nullptr
)
if
(
vi
!=
nullptr
)
{
{
seen
=
true
;
seen
=
true
;
try
std
::
error_code
ec
;
{
(
*
iv
)(
vi
->
text
()
);
iv
->
validate_value
(
vi
->
text
(),
ec
);
}
catch
(
const
std
::
exception
&
e
)
if
(
ec
!=
std
::
errc
()
)
{
{
result
=
false
;
m_validator
->
report_error
(
ec
,
m_name
,
m_items
[
cix
].
m_name
,
false
);
m_validator
->
report_error
(
"Error validating "
+
m_columns
[
cix
].
m_name
+
": "
+
e
.
what
(),
false
);
continue
;
continue
;
}
}
}
}
...
@@ -857,7 +856,7 @@ bool category::is_valid() const
...
@@ -857,7 +856,7 @@ bool category::is_valid() const
if
(
iv
!=
nullptr
and
iv
->
m_mandatory
)
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
;
result
=
false
;
}
}
}
}
...
@@ -989,10 +988,10 @@ condition category::get_children_condition(row_handle rh, const category &childC
...
@@ -989,10 +988,10 @@ condition category::get_children_condition(row_handle rh, const category &childC
condition
result
;
condition
result
;
iset
mandatoryChild
Field
s
;
iset
mandatoryChild
Item
s
;
auto
childCatValidator
=
m_validator
->
get_validator_for_category
(
childCat
.
name
());
auto
childCatValidator
=
m_validator
->
get_validator_for_category
(
childCat
.
name
());
if
(
childCatValidator
!=
nullptr
)
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
);
auto
links
=
m_validator
->
get_links_for_parent
(
m_name
);
links
.
erase
(
remove_if
(
links
.
begin
(),
links
.
end
(),
[
n
=
childCat
.
m_name
](
auto
&
l
)
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
...
@@ -1014,7 +1013,7 @@ condition category::get_children_condition(row_handle rh, const category &childC
if
(
parentValue
.
empty
())
if
(
parentValue
.
empty
())
cond
=
std
::
move
(
cond
)
and
key
(
childKey
)
==
null
;
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
);
cond
=
std
::
move
(
cond
)
and
(
key
(
childKey
)
==
parentValue
.
text
()
or
key
(
childKey
)
==
null
);
else
else
cond
=
std
::
move
(
cond
)
and
key
(
childKey
)
==
parentValue
.
text
();
cond
=
std
::
move
(
cond
)
and
key
(
childKey
)
==
parentValue
.
text
();
...
@@ -1347,11 +1346,11 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
...
@@ -1347,11 +1346,11 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
if
(
rows
.
empty
())
if
(
rows
.
empty
())
return
;
return
;
auto
colIx
=
get_
column
_ix
(
tag
);
auto
colIx
=
get_
item
_ix
(
tag
);
if
(
colIx
>=
m_
column
s
.
size
())
if
(
colIx
>=
m_
item
s
.
size
())
throw
std
::
runtime_error
(
"Invalid
column
"
+
std
::
string
{
value
}
+
" for "
+
m_name
);
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
// check the value
if
(
col
.
m_validator
)
if
(
col
.
m_validator
)
...
@@ -1469,17 +1468,17 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
...
@@ -1469,17 +1468,17 @@ void category::update_value(const std::vector<row_handle> &rows, std::string_vie
}
}
}
}
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
// make sure we have an index, if possible
if
((
updateLinked
or
validate
)
and
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
if
((
updateLinked
or
validate
)
and
m_index
==
nullptr
and
m_cat_validator
!=
nullptr
)
m_index
=
new
category_index
(
*
this
);
m_index
=
new
category_index
(
*
this
);
auto
&
col
=
m_
columns
[
column
];
auto
&
col
=
m_
items
[
item
];
std
::
string_view
oldValue
;
std
::
string_view
oldValue
;
auto
ival
=
row
->
get
(
column
);
auto
ival
=
row
->
get
(
item
);
if
(
ival
!=
nullptr
)
if
(
ival
!=
nullptr
)
oldValue
=
ival
->
text
();
oldValue
=
ival
->
text
();
...
@@ -1492,12 +1491,12 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
...
@@ -1492,12 +1491,12 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
if
(
col
.
m_validator
and
validate
)
if
(
col
.
m_validator
and
validate
)
col
.
m_validator
->
operator
()(
value
);
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
// before updating
bool
reinsert
=
false
;
bool
reinsert
=
false
;
if
(
updateLinked
and
// an update of an Item's value
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
);
reinsert
=
m_index
->
find
(
*
this
,
row
);
if
(
reinsert
)
if
(
reinsert
)
...
@@ -1506,10 +1505,10 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
...
@@ -1506,10 +1505,10 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
// first remove old value with cix
// first remove old value with cix
if
(
ival
!=
nullptr
)
if
(
ival
!=
nullptr
)
row
->
remove
(
column
);
row
->
remove
(
item
);
if
(
not
value
.
empty
())
if
(
not
value
.
empty
())
row
->
append
(
column
,
{
value
});
row
->
append
(
item
,
{
value
});
if
(
reinsert
and
m_index
!=
nullptr
)
if
(
reinsert
and
m_index
!=
nullptr
)
m_index
->
insert
(
*
this
,
row
);
m_index
->
insert
(
*
this
,
row
);
...
@@ -1533,7 +1532,7 @@ void category::update_value(row *row, uint16_t column, std::string_view value, b
...
@@ -1533,7 +1532,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
pk
=
linked
->
m_parent_keys
[
ix
];
std
::
string
ck
=
linked
->
m_child_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_tag
)
{
{
...
@@ -1640,7 +1639,7 @@ row_handle category::create_copy(row_handle r)
...
@@ -1640,7 +1639,7 @@ row_handle category::create_copy(row_handle r)
{
{
auto
i
=
r
.
m_row
->
get
(
ix
);
auto
i
=
r
.
m_row
->
get
(
ix
);
if
(
i
!=
nullptr
)
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
)
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)
...
@@ -1683,12 +1682,12 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
try
try
{
{
// First, make sure all mandatory
field
s are supplied
// First, make sure all mandatory
item
s are supplied
if
(
m_cat_validator
!=
nullptr
)
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
)
if
(
iv
==
nullptr
)
continue
;
continue
;
...
@@ -1703,7 +1702,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
...
@@ -1703,7 +1702,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
}
}
if
(
not
seen
and
iv
->
m_mandatory
)
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)
...
@@ -1742,7 +1741,7 @@ category::iterator category::insert_impl(const_iterator pos, row *n)
// #endif
// #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
==
a
.
m_category
);
assert
(
this
==
b
.
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)
...
@@ -1750,7 +1749,7 @@ void category::swap_item(uint16_t column_ix, row_handle &a, row_handle &b)
auto
&
ra
=
*
a
.
m_row
;
auto
&
ra
=
*
a
.
m_row
;
auto
&
rb
=
*
b
.
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
)
void
category
::
sort
(
std
::
function
<
int
(
row_handle
,
row_handle
)
>
f
)
...
@@ -1790,7 +1789,7 @@ namespace detail
...
@@ -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
)
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
)
if
(
offset
>
0
)
os
<<
'\n'
;
os
<<
'\n'
;
...
@@ -1888,33 +1887,33 @@ namespace detail
...
@@ -1888,33 +1887,33 @@ namespace detail
std
::
vector
<
std
::
string
>
category
::
get_tag_order
()
const
std
::
vector
<
std
::
string
>
category
::
get_tag_order
()
const
{
{
std
::
vector
<
std
::
string
>
result
;
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
);
result
.
push_back
(
"_"
+
m_name
+
"."
+
c
.
m_name
);
return
result
;
return
result
;
}
}
void
category
::
write
(
std
::
ostream
&
os
)
const
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
));
iota
(
order
.
begin
(),
order
.
end
(),
static_cast
<
uint16_t
>
(
0
));
write
(
os
,
order
,
false
);
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
// make sure all
item
s are present
for
(
auto
&
c
:
column
s
)
for
(
auto
&
c
:
item
s
)
add_
column
(
c
);
add_
item
(
c
);
std
::
vector
<
uint16_t
>
order
;
std
::
vector
<
uint16_t
>
order
;
order
.
reserve
(
m_
column
s
.
size
());
order
.
reserve
(
m_
item
s
.
size
());
for
(
auto
&
c
:
column
s
)
for
(
auto
&
c
:
item
s
)
order
.
push_back
(
get_
column
_ix
(
c
));
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
())
if
(
std
::
find
(
order
.
begin
(),
order
.
end
(),
i
)
==
order
.
end
())
order
.
push_back
(
i
);
order
.
push_back
(
i
);
...
@@ -1924,7 +1923,7 @@ void category::write(std::ostream &os, const std::vector<std::string> &columns,
...
@@ -1924,7 +1923,7 @@ void category::write(std::ostream &os, const std::vector<std::string> &columns,
write
(
os
,
order
,
true
);
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
())
if
(
empty
())
return
;
return
;
...
@@ -1932,13 +1931,13 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
...
@@ -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_
// If the first Row has a next, we need a loop_
bool
needLoop
=
(
m_head
->
m_next
!=
nullptr
);
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
)
if
(
m_cat_validator
!=
nullptr
)
{
{
for
(
auto
cix
:
order
)
for
(
auto
cix
:
order
)
{
{
auto
&
col
=
m_
column
s
[
cix
];
auto
&
col
=
m_
item
s
[
cix
];
right_aligned
[
cix
]
=
col
.
m_validator
!=
nullptr
and
right_aligned
[
cix
]
=
col
.
m_validator
!=
nullptr
and
col
.
m_validator
->
m_type
!=
nullptr
and
col
.
m_validator
->
m_type
!=
nullptr
and
col
.
m_validator
->
m_type
->
m_primitive_type
==
cif
::
DDL_PrimitiveType
::
Numb
;
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
...
@@ -1949,16 +1948,16 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
{
{
os
<<
"loop_
\n
"
;
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
)
for
(
auto
cix
:
order
)
{
{
auto
&
col
=
m_
column
s
[
cix
];
auto
&
col
=
m_
item
s
[
cix
];
os
<<
'_'
;
os
<<
'_'
;
if
(
not
m_name
.
empty
())
if
(
not
m_name
.
empty
())
os
<<
m_name
<<
'.'
;
os
<<
m_name
<<
'.'
;
os
<<
col
.
m_name
<<
' '
<<
'\n'
;
os
<<
col
.
m_name
<<
' '
<<
'\n'
;
column
Widths
[
cix
]
=
2
;
item
Widths
[
cix
]
=
2
;
}
}
for
(
auto
r
=
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
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
...
@@ -1979,8 +1978,8 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
if
(
l
>
132
)
if
(
l
>
132
)
continue
;
continue
;
if
(
column
Widths
[
ix
]
<
l
+
1
)
if
(
item
Widths
[
ix
]
<
l
+
1
)
column
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
...
@@ -1991,7 +1990,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
for
(
uint16_t
cix
:
order
)
for
(
uint16_t
cix
:
order
)
{
{
size_t
w
=
column
Widths
[
cix
];
size_t
w
=
item
Widths
[
cix
];
std
::
string_view
s
;
std
::
string_view
s
;
auto
iv
=
r
->
get
(
cix
);
auto
iv
=
r
->
get
(
cix
);
...
@@ -2031,7 +2030,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
...
@@ -2031,7 +2030,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
// first find the indent level
// first find the indent level
size_t
l
=
0
;
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
tag
=
'_'
+
m_name
+
'.'
+
col
.
m_name
;
...
@@ -2067,7 +2066,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
...
@@ -2067,7 +2066,7 @@ void category::write(std::ostream &os, const std::vector<uint16_t> &order, bool
for
(
uint16_t
cix
:
order
)
for
(
uint16_t
cix
:
order
)
{
{
auto
&
col
=
m_
column
s
[
cix
];
auto
&
col
=
m_
item
s
[
cix
];
os
<<
'_'
;
os
<<
'_'
;
if
(
not
m_name
.
empty
())
if
(
not
m_name
.
empty
())
...
@@ -2108,10 +2107,10 @@ bool category::operator==(const category &rhs) const
...
@@ -2108,10 +2107,10 @@ bool category::operator==(const category &rhs) const
using
namespace
std
::
placeholders
;
using
namespace
std
::
placeholders
;
// set<std::string> tagsA(a.
fields()), tagsB(b.field
s());
// set<std::string> tagsA(a.
items()), tagsB(b.item
s());
//
//
// if (tagsA != tagsB)
// if (tagsA != tagsB)
// std::cout << "Unequal number of
field
s\n";
// std::cout << "Unequal number of
item
s\n";
const
category_validator
*
catValidator
=
nullptr
;
const
category_validator
*
catValidator
=
nullptr
;
...
@@ -2126,7 +2125,7 @@ bool category::operator==(const category &rhs) const
...
@@ -2126,7 +2125,7 @@ bool category::operator==(const category &rhs) const
if
(
catValidator
==
nullptr
)
if
(
catValidator
==
nullptr
)
{
{
for
(
auto
&
tag
:
a
.
get_
column
s
())
for
(
auto
&
tag
:
a
.
get_
item
s
())
{
{
tags
.
push_back
(
std
::
make_tuple
(
tag
,
[](
std
::
string_view
va
,
std
::
string_view
vb
)
tags
.
push_back
(
std
::
make_tuple
(
tag
,
[](
std
::
string_view
va
,
std
::
string_view
vb
)
{
return
va
.
compare
(
vb
);
}));
{
return
va
.
compare
(
vb
);
}));
...
@@ -2138,7 +2137,7 @@ bool category::operator==(const category &rhs) const
...
@@ -2138,7 +2137,7 @@ bool category::operator==(const category &rhs) const
{
{
keys
=
catValidator
->
m_keys
;
keys
=
catValidator
->
m_keys
;
for
(
auto
&
tag
:
a
.
key_
field
s
())
for
(
auto
&
tag
:
a
.
key_
item
s
())
{
{
auto
iv
=
catValidator
->
get_validator_for_item
(
tag
);
auto
iv
=
catValidator
->
get_validator_for_item
(
tag
);
if
(
iv
==
nullptr
)
if
(
iv
==
nullptr
)
...
...
src/condition.cpp
View file @
2792caec
...
@@ -30,17 +30,17 @@
...
@@ -30,17 +30,17 @@
namespace
cif
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
;
bool
result
=
false
;
...
@@ -63,12 +63,12 @@ namespace detail
...
@@ -63,12 +63,12 @@ namespace detail
condition_impl
*
key_equals_condition_impl
::
prepare
(
const
category
&
c
)
condition_impl
*
key_equals_condition_impl
::
prepare
(
const
category
&
c
)
{
{
m_item_ix
=
c
.
get_
column
_ix
(
m_item_tag
);
m_item_ix
=
c
.
get_
item
_ix
(
m_item_tag
);
m_icase
=
is_
column
_type_uchar
(
c
,
m_item_tag
);
m_icase
=
is_
item
_type_uchar
(
c
,
m_item_tag
);
if
(
c
.
get_cat_validator
()
!=
nullptr
and
if
(
c
.
get_cat_validator
()
!=
nullptr
and
c
.
key_
field
_indices
().
contains
(
m_item_ix
)
and
c
.
key_
item
_indices
().
contains
(
m_item_ix
)
and
c
.
key_
field
_indices
().
size
()
==
1
)
c
.
key_
item
_indices
().
size
()
==
1
)
{
{
m_single_hit
=
c
[{
{
m_item_tag
,
m_value
}
}];
m_single_hit
=
c
[{
{
m_item_tag
,
m_value
}
}];
}
}
...
...
src/item.cpp
View file @
2792caec
...
@@ -35,7 +35,7 @@ const item_handle item_handle::s_null_item;
...
@@ -35,7 +35,7 @@ const item_handle item_handle::s_null_item;
row_handle
s_null_row_handle
;
row_handle
s_null_row_handle
;
item_handle
::
item_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
)
,
m_row_handle
(
s_null_row_handle
)
{
{
}
}
...
@@ -44,7 +44,7 @@ std::string_view item_handle::text() const
...
@@ -44,7 +44,7 @@ std::string_view item_handle::text() const
{
{
if
(
not
m_row_handle
.
empty
())
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
)
if
(
iv
!=
nullptr
)
return
iv
->
text
();
return
iv
->
text
();
}
}
...
@@ -55,14 +55,14 @@ std::string_view item_handle::text() const
...
@@ -55,14 +55,14 @@ std::string_view item_handle::text() const
void
item_handle
::
assign_value
(
const
item
&
v
)
void
item_handle
::
assign_value
(
const
item
&
v
)
{
{
assert
(
not
m_row_handle
.
empty
());
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
)
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);
// assert(&m_row_handle.m_category == &b.m_row_handle.m_category);
m_row_handle
.
swap
(
m_
column
,
b
.
m_row_handle
);
m_row_handle
.
swap
(
m_
item_ix
,
b
.
m_row_handle
);
}
}
}
}
src/parser.cpp
View file @
2792caec
...
@@ -300,7 +300,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
...
@@ -300,7 +300,7 @@ sac_parser::CIFToken sac_parser::get_next_token()
else
if
(
ch
==
'_'
)
else
if
(
ch
==
'_'
)
state
=
State
::
Tag
;
state
=
State
::
Tag
;
else
if
(
ch
==
';'
and
m_bol
)
else
if
(
ch
==
';'
and
m_bol
)
state
=
State
::
Text
Field
;
state
=
State
::
Text
Item
;
else
if
(
ch
==
'?'
)
else
if
(
ch
==
'?'
)
state
=
State
::
QuestionMark
;
state
=
State
::
QuestionMark
;
else
if
(
ch
==
'\''
or
ch
==
'"'
)
else
if
(
ch
==
'\''
or
ch
==
'"'
)
...
@@ -350,18 +350,18 @@ sac_parser::CIFToken sac_parser::get_next_token()
...
@@ -350,18 +350,18 @@ sac_parser::CIFToken sac_parser::get_next_token()
state
=
State
::
Value
;
state
=
State
::
Value
;
break
;
break
;
case
State
:
:
Text
Field
:
case
State
:
:
Text
Item
:
if
(
ch
==
'\n'
)
if
(
ch
==
'\n'
)
state
=
State
::
Text
Field
NL
;
state
=
State
::
Text
Item
NL
;
else
if
(
ch
==
kEOF
)
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
error
(
"unterminated textfield"
);
else
if
(
not
is_any_print
(
ch
)
and
cif
::
VERBOSE
>
2
)
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
)
+
")"
);
warning
(
"invalid character in text field '"
+
std
::
string
({
static_cast
<
char
>
(
ch
)})
+
"' ("
+
std
::
to_string
((
int
)
ch
)
+
")"
);
break
;
break
;
case
State
:
:
Text
Field
NL
:
case
State
:
:
Text
Item
NL
:
if
(
is_text_lead
(
ch
)
or
ch
==
' '
or
ch
==
'\t'
)
if
(
is_text_lead
(
ch
)
or
ch
==
' '
or
ch
==
'\t'
)
state
=
State
::
Text
Field
;
state
=
State
::
Text
Item
;
else
if
(
ch
==
';'
)
else
if
(
ch
==
';'
)
{
{
assert
(
m_token_buffer
.
size
()
>=
2
);
assert
(
m_token_buffer
.
size
()
>=
2
);
...
...
src/pdb/pdb2cif_remark_3.cpp
View file @
2792caec
...
@@ -1493,8 +1493,8 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
...
@@ -1493,8 +1493,8 @@ bool Remark3Parser::parse(const std::string &expMethod, PDBRecord *r, cif::datab
auto
r1
=
cat1
.
front
();
auto
r1
=
cat1
.
front
();
auto
r2
=
cat2
.
front
();
auto
r2
=
cat2
.
front
();
for
(
auto
column
:
cat1
.
key_field
s
())
for
(
auto
item
:
cat1
.
key_item
s
())
r2
[
column
]
=
r1
[
column
].
text
();
r2
[
item
]
=
r1
[
item
].
text
();
}
}
}
}
else
else
...
...
src/pdb/reconstruct.cpp
View file @
2792caec
...
@@ -237,7 +237,7 @@ void checkAtomRecords(datablock &db)
...
@@ -237,7 +237,7 @@ void checkAtomRecords(datablock &db)
{
"auth_comp_id"
,
auth_comp_id
.
value_or
(
*
label_comp_id
)
},
{
"auth_comp_id"
,
auth_comp_id
.
value_or
(
*
label_comp_id
)
},
{
"auth_atom_id"
,
auth_atom_id
.
value_or
(
*
label_atom_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
// 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
[
tag
,
prec
]
:
std
::
vector
<
std
::
tuple
<
std
::
string_view
,
std
::
string
::
size_type
>>
{
{
"cartn_x"
,
3
},
{
"cartn_x"
,
3
},
...
@@ -267,8 +267,8 @@ void checkAtomRecords(datablock &db)
...
@@ -267,8 +267,8 @@ void checkAtomRecords(datablock &db)
auto
*
cv
=
atom_site
.
get_cat_validator
();
auto
*
cv
=
atom_site
.
get_cat_validator
();
if
(
cv
)
if
(
cv
)
{
{
// See if there are
column
s that are no longer known
// See if there are
item
s that are no longer known
for
(
auto
tag
:
atom_site
.
get_
column
s
())
for
(
auto
tag
:
atom_site
.
get_
item
s
())
{
{
if
(
cv
->
get_validator_for_item
(
tag
)
!=
nullptr
)
if
(
cv
->
get_validator_for_item
(
tag
)
!=
nullptr
)
continue
;
continue
;
...
@@ -277,12 +277,12 @@ void checkAtomRecords(datablock &db)
...
@@ -277,12 +277,12 @@ void checkAtomRecords(datablock &db)
if
(
not
r
)
if
(
not
r
)
{
{
if
(
cif
::
VERBOSE
>
0
)
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Dropping unknown
column
"
<<
tag
<<
'\n'
;
std
::
clog
<<
"Dropping unknown
item
"
<<
tag
<<
'\n'
;
atom_site
.
remove_
column
(
tag
);
atom_site
.
remove_
item
(
tag
);
}
}
else
if
(
cif
::
VERBOSE
>
0
)
else
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Keeping unknown
column
"
<<
std
::
quoted
(
tag
)
<<
" in atom_site since it is not empty
\n
"
;
std
::
clog
<<
"Keeping unknown
item
"
<<
std
::
quoted
(
tag
)
<<
" in atom_site since it is not empty
\n
"
;
}
}
}
}
}
}
...
@@ -311,10 +311,10 @@ void createEntity(datablock &db)
...
@@ -311,10 +311,10 @@ void createEntity(datablock &db)
auto
&
cf
=
compound_factory
::
instance
();
auto
&
cf
=
compound_factory
::
instance
();
auto
&
atom_site
=
db
[
"atom_site"
];
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"
];
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
;
std
::
map
<
std
::
string
,
std
::
vector
<
std
::
tuple
<
std
::
string
,
int
>>>
asyms
;
...
@@ -617,7 +617,7 @@ void comparePolySeqSchemes(datablock &db)
...
@@ -617,7 +617,7 @@ void comparePolySeqSchemes(datablock &db)
auto
&
ndb_poly_seq_scheme
=
db
[
"ndb_poly_seq_scheme"
];
auto
&
ndb_poly_seq_scheme
=
db
[
"ndb_poly_seq_scheme"
];
auto
&
pdbx_poly_seq_scheme
=
db
[
"pdbx_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
// we assume that it should match the accompanying pdbx_poly_seq
std
::
vector
<
std
::
string
>
asym_ids_ndb
,
asym_ids_pdbx
;
std
::
vector
<
std
::
string
>
asym_ids_ndb
,
asym_ids_pdbx
;
...
@@ -722,6 +722,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
...
@@ -722,6 +722,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
std
::
vector
<
std
::
string
>
invalidCategories
;
std
::
vector
<
std
::
string
>
invalidCategories
;
// clean up each category
for
(
auto
&
cat
:
db
)
for
(
auto
&
cat
:
db
)
{
{
try
try
...
@@ -730,12 +731,12 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
...
@@ -730,12 +731,12 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
if
(
not
cv
)
if
(
not
cv
)
continue
;
continue
;
// Start by renaming
column
s that may have old names based on alias info
// Start by renaming
item
s that may have old names based on alias info
for
(
auto
tag
:
cat
.
get_
column
s
())
for
(
auto
tag
:
cat
.
get_
item
s
())
{
{
auto
iv
=
cv
->
get_validator_for_item
(
tag
);
auto
iv
=
cv
->
get_validator_for_item
(
tag
);
if
(
iv
)
// know, must be OK then
if
(
iv
)
// know, must be OK then
`
continue
;
continue
;
iv
=
cv
->
get_validator_for_aliased_item
(
tag
);
iv
=
cv
->
get_validator_for_aliased_item
(
tag
);
...
@@ -744,7 +745,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
...
@@ -744,7 +745,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
if
(
cif
::
VERBOSE
>
0
)
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Renaming "
<<
tag
<<
" to "
<<
iv
->
m_tag
<<
" in category "
<<
cat
.
name
()
<<
'\n'
;
std
::
clog
<<
"Renaming "
<<
tag
<<
" to "
<<
iv
->
m_tag
<<
" in category "
<<
cat
.
name
()
<<
'\n'
;
cat
.
rename_
column
(
tag
,
iv
->
m_tag
);
cat
.
rename_
item
(
tag
,
iv
->
m_tag
);
}
}
for
(
auto
link
:
validator
.
get_links_for_child
(
cat
.
name
()))
for
(
auto
link
:
validator
.
get_links_for_child
(
cat
.
name
()))
...
@@ -767,14 +768,38 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
...
@@ -767,14 +768,38 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
}
}
}
}
// Fill in all mandatory
field
s
// Fill in all mandatory
item
s
for
(
auto
key
:
cv
->
m_mandatory_
field
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
)
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Adding mandatory key "
<<
key
<<
" to category "
<<
cat
.
name
()
<<
'\n'
;
std
::
clog
<<
"Adding mandatory key "
<<
key
<<
" to category "
<<
cat
.
name
()
<<
'\n'
;
cat
.
add_column
(
key
);
cat
.
add_item
(
key
);
}
}
// validate all values, and if they do not validate replace the content with an unknown flag
for
(
auto
tag
:
cat
.
get_items
())
{
auto
iv
=
cv
->
get_validator_for_item
(
tag
);
if
(
not
iv
)
continue
;
auto
ix
=
cat
.
get_item_ix
(
tag
);
for
(
auto
row
:
cat
)
{
std
::
error_code
ec
;
std
::
string_view
value
=
row
[
ix
].
text
();
if
(
not
iv
->
validate_value
(
value
,
ec
))
{
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Replacing value ("
<<
std
::
quoted
(
value
)
<<
") for item "
<<
tag
<<
" since it does not validate
\n
"
;
row
[
ix
]
=
"?"
;
}
}
}
}
}
...
@@ -834,7 +859,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
...
@@ -834,7 +859,7 @@ void reconstruct_pdbx(file &file, std::string_view dictionary)
if
(
cif
::
VERBOSE
>
0
)
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
"Attempt to fix "
<<
cat
.
name
()
<<
" failed: "
<<
ex
.
what
()
<<
'\n'
;
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
;
std
::
set
<
std
::
string
>
replaceableKeys
;
for
(
auto
key
:
cv
->
m_keys
)
for
(
auto
key
:
cv
->
m_keys
)
...
...
src/pdb/validate-pdbx.cpp
View file @
2792caec
...
@@ -69,26 +69,67 @@ condition get_parents_condition(const validator &validator, row_handle rh, const
...
@@ -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
)
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
;
}
auto
&
cf
=
cif
::
compound_factory
::
instance
();
bool
is_valid_pdbx_file
(
const
file
&
file
,
std
::
error_code
&
ec
)
auto
&
validator
=
cif
::
validator_factory
::
instance
().
operator
[](
dictionary
);
{
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
>
();
}
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
;
bool
result
=
true
;
try
try
{
{
auto
&
cf
=
cif
::
compound_factory
::
instance
();
auto
&
validator
=
cif
::
validator_factory
::
instance
().
operator
[](
dictionary
);
if
(
file
.
empty
())
if
(
file
.
empty
())
throw
validation
_error
(
"Empty file"
);
throw
std
::
runtime
_error
(
"Empty file"
);
auto
&
db
=
file
.
front
();
auto
&
db
=
file
.
front
();
if
(
db
.
empty
())
if
(
db
.
empty
())
throw
validation
_error
(
"Empty datablock"
);
throw
std
::
runtime
_error
(
"Empty datablock"
);
auto
&
atom_site
=
db
[
"atom_site"
];
auto
&
atom_site
=
db
[
"atom_site"
];
if
(
atom_site
.
empty
())
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"
];
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)
...
@@ -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
));
auto
p
=
pdbx_poly_seq_scheme
.
find
(
get_parents_condition
(
validator
,
r
,
pdbx_poly_seq_scheme
));
if
(
p
.
size
()
!=
1
)
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"
];
auto
&
entity
=
db
[
"entity"
];
if
(
entity
.
empty
())
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"
];
auto
&
entity_poly
=
db
[
"entity_poly"
];
if
(
entity_poly
.
empty
())
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"
];
auto
&
entity_poly_seq
=
db
[
"entity_poly_seq"
];
if
(
entity_poly_seq
.
empty
())
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"
];
auto
&
struct_asym
=
db
[
"struct_asym"
];
if
(
struct_asym
.
empty
())
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"
))
for
(
auto
entity_id
:
entity
.
find
<
std
::
string
>
(
"type"
_key
==
"polymer"
,
"id"
))
{
{
if
(
entity_poly
.
count
(
"entity_id"
_key
==
entity_id
)
!=
1
)
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"
);
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)
...
@@ -151,7 +192,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
"seq_id"
_key
==
num
and
"seq_id"
_key
==
num
and
"hetero"
_key
==
hetero
)
!=
1
)
"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)
...
@@ -163,11 +204,11 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
"num"
_key
==
seq_id
and
"num"
_key
==
seq_id
and
"hetero"
_key
==
hetero
)
!=
1
)
"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
)
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
)
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)
...
@@ -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
);
"label_seq_id"
_key
==
seq_id
and
not
std
::
move
(
cond
);
if
(
atom_site
.
contains
(
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)
...
@@ -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
());
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
()))
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
())
if
(
not
seq_can
.
has_value
())
...
@@ -263,7 +304,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
...
@@ -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
());
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
()))
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)
...
@@ -275,6 +316,7 @@ bool is_valid_pdbx_file(const file &file, std::string_view dictionary)
result
=
false
;
result
=
false
;
if
(
cif
::
VERBOSE
>
0
)
if
(
cif
::
VERBOSE
>
0
)
std
::
clog
<<
ex
.
what
()
<<
'\n'
;
std
::
clog
<<
ex
.
what
()
<<
'\n'
;
ec
=
make_error_code
(
validation_error
::
not_valid_pdbx
);
}
}
return
result
;
return
result
;
...
...
src/row.cpp
View file @
2792caec
...
@@ -29,44 +29,44 @@
...
@@ -29,44 +29,44 @@
namespace
cif
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
)
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
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
)
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
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
)
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
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
)
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
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
)
if
(
not
m_category
)
throw
std
::
runtime_error
(
"uninitialized row"
);
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)
...
@@ -86,7 +86,7 @@ row_initializer::row_initializer(row_handle rh)
auto
&
i
=
r
->
operator
[](
ix
);
auto
&
i
=
r
->
operator
[](
ix
);
if
(
not
i
)
if
(
not
i
)
continue
;
continue
;
emplace_back
(
cat
.
get_
column
_name
(
ix
),
i
.
text
());
emplace_back
(
cat
.
get_
item
_name
(
ix
),
i
.
text
());
}
}
}
}
...
...
src/validate.cpp
View file @
2792caec
...
@@ -39,10 +39,10 @@
...
@@ -39,10 +39,10 @@
// the code will use boost::regex instead.
// the code will use boost::regex instead.
#if USE_BOOST_REGEX
#if USE_BOOST_REGEX
#include <boost/regex.hpp>
#
include <boost/regex.hpp>
using
boost
::
regex
;
using
boost
::
regex
;
#else
#else
#include <regex>
#
include <regex>
using
std
::
regex
;
using
std
::
regex
;
#endif
#endif
...
@@ -57,20 +57,11 @@ struct regex_impl : public regex
...
@@ -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
;
DDL_PrimitiveType
result
;
if
(
iequals
(
s
,
"char"
))
if
(
iequals
(
s
,
"char"
))
result
=
DDL_PrimitiveType
::
Char
;
result
=
DDL_PrimitiveType
::
Char
;
...
@@ -79,7 +70,16 @@ DDL_PrimitiveType map_to_primitive_type(std::string_view s)
...
@@ -79,7 +70,16 @@ DDL_PrimitiveType map_to_primitive_type(std::string_view s)
else
if
(
iequals
(
s
,
"numb"
))
else
if
(
iequals
(
s
,
"numb"
))
result
=
DDL_PrimitiveType
::
Numb
;
result
=
DDL_PrimitiveType
::
Numb
;
else
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
;
return
result
;
}
}
...
@@ -218,17 +218,24 @@ int type_validator::compare(std::string_view a, std::string_view b) const
...
@@ -218,17 +218,24 @@ int type_validator::compare(std::string_view a, std::string_view b) const
void
item_validator
::
operator
()(
std
::
string_view
value
)
const
void
item_validator
::
operator
()(
std
::
string_view
value
)
const
{
{
std
::
error_code
ec
;
if
(
not
validate_value
(
value
,
ec
))
throw
std
::
system_error
(
ec
,
std
::
string
{
value
}
+
" does not match rx for "
+
m_tag
);
}
bool
item_validator
::
validate_value
(
std
::
string_view
value
,
std
::
error_code
&
ec
)
const
noexcept
{
ec
=
{};
if
(
not
value
.
empty
()
and
value
!=
"?"
and
value
!=
"."
)
if
(
not
value
.
empty
()
and
value
!=
"?"
and
value
!=
"."
)
{
{
if
(
m_type
!=
nullptr
and
not
regex_match
(
value
.
begin
(),
value
.
end
(),
*
m_type
->
m_rx
))
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
);
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
)
if
(
not
m_enums
.
empty
())
ec
=
make_error_code
(
validation_error
::
value_is_not_in_enumeration_list
);
{
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"
);
}
}
}
return
ec
==
std
::
errc
();
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -236,7 +243,7 @@ void item_validator::operator()(std::string_view value) const
...
@@ -236,7 +243,7 @@ void item_validator::operator()(std::string_view value) const
void
category_validator
::
add_item_validator
(
item_validator
&&
v
)
void
category_validator
::
add_item_validator
(
item_validator
&&
v
)
{
{
if
(
v
.
m_mandatory
)
if
(
v
.
m_mandatory
)
m_mandatory_
field
s
.
insert
(
v
.
m_tag
);
m_mandatory_
item
s
.
insert
(
v
.
m_tag
);
v
.
m_category
=
this
;
v
.
m_category
=
this
;
...
@@ -265,7 +272,7 @@ const item_validator *category_validator::get_validator_for_aliased_item(std::st
...
@@ -265,7 +272,7 @@ const item_validator *category_validator::get_validator_for_aliased_item(std::st
for
(
auto
&
ai
:
iv
.
m_aliases
)
for
(
auto
&
ai
:
iv
.
m_aliases
)
{
{
const
auto
&
[
cat
,
name
]
=
split_tag_name
(
ai
.
m_name
);
const
auto
&
[
cat
,
name
]
=
split_tag_name
(
ai
.
m_name
);
if
(
name
==
tag
and
cat
==
m_name
)
if
(
iequals
(
name
,
tag
)
and
iequals
(
cat
,
m_name
)
)
{
{
result
=
&
iv
;
result
=
&
iv
;
break
;
break
;
...
@@ -373,7 +380,7 @@ std::vector<const link_validator *> validator::get_links_for_parent(std::string_
...
@@ -373,7 +380,7 @@ std::vector<const link_validator *> validator::get_links_for_parent(std::string_
for
(
auto
&
l
:
m_link_validators
)
for
(
auto
&
l
:
m_link_validators
)
{
{
if
(
l
.
m_parent_category
==
category
)
if
(
iequals
(
l
.
m_parent_category
,
category
)
)
result
.
push_back
(
&
l
);
result
.
push_back
(
&
l
);
}
}
...
@@ -386,19 +393,41 @@ std::vector<const link_validator *> validator::get_links_for_child(std::string_v
...
@@ -386,19 +393,41 @@ std::vector<const link_validator *> validator::get_links_for_child(std::string_v
for
(
auto
&
l
:
m_link_validators
)
for
(
auto
&
l
:
m_link_validators
)
{
{
if
(
l
.
m_child_category
==
category
)
if
(
iequals
(
l
.
m_child_category
,
category
)
)
result
.
push_back
(
&
l
);
result
.
push_back
(
&
l
);
}
}
return
result
;
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
)
if
(
m_strict
or
fatal
)
throw
validation_error
(
msg
);
throw
std
::
system_error
(
ec
);
else
if
(
VERBOSE
>
0
)
else
std
::
cerr
<<
msg
<<
'\n'
;
std
::
cerr
<<
ec
.
message
()
<<
'\n'
;
}
void
validator
::
report_error
(
std
::
error_code
ec
,
std
::
string_view
category
,
std
::
string_view
item
,
bool
fatal
)
const
{
std
::
ostringstream
os
;
os
<<
"category: "
<<
category
;
if
(
not
item
.
empty
())
os
<<
"; item: "
<<
item
;
if
(
m_strict
or
fatal
)
throw
std
::
system_error
(
ec
,
os
.
str
());
else
std
::
cerr
<<
ec
.
message
()
<<
": "
<<
os
.
str
()
<<
'\n'
;
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -460,12 +489,12 @@ const validator &validator_factory::operator[](std::string_view dictionary_name)
...
@@ -460,12 +489,12 @@ const validator &validator_factory::operator[](std::string_view dictionary_name)
if
(
not
std
::
filesystem
::
exists
(
p
,
ec
)
or
ec
)
if
(
not
std
::
filesystem
::
exists
(
p
,
ec
)
or
ec
)
{
{
for
(
const
char
*
dir
:
{
for
(
const
char
*
dir
:
{
#if defined(CACHE_DIR)
#
if defined(CACHE_DIR)
CACHE_DIR
,
CACHE_DIR
,
#endif
#
endif
#if defined(DATA_DIR)
#
if defined(DATA_DIR)
DATA_DIR
DATA_DIR
#endif
#
endif
})
})
{
{
auto
p2
=
std
::
filesystem
::
path
(
dir
)
/
p
;
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