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
821895bb
Unverified
Commit
821895bb
authored
Sep 05, 2023
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
backup of documentation
parent
3f437277
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
277 additions
and
28 deletions
+277
-28
include/cif++/compound.hpp
+11
-5
include/cif++/condition.hpp
+239
-19
src/compound.cpp
+27
-4
No files found.
include/cif++/compound.hpp
View file @
821895bb
...
...
@@ -72,10 +72,10 @@ enum class bond_type
};
/// @brief return the string representation of @ref bond_type @a bondType
std
::
string
to_string
(
bond_type
bondType
);
std
::
string
bond_type_
to_string
(
bond_type
bondType
);
/// @brief return the @ref bond_type for the string representation @a bondType
bond_type
from_string
(
const
std
::
string
&
bondType
);
bond_type
parse_bond_type_
from_string
(
const
std
::
string
&
bondType
);
/// \brief The possible stereo config values for a compound_atom.
///
...
...
@@ -89,11 +89,17 @@ bond_type from_string(const std::string &bondType);
/// > referred to ‘S isomers’.
enum
class
stereo_config_type
:
uint8_t
{
N
=
'N'
,
R
=
'R'
,
S
=
'S'
N
=
'N'
,
///< Not polarizing
R
=
'R'
,
///< Rectus
S
=
'S'
///< Sinister
};
/// @brief return the string representation of @ref stereo_config_type @a stereo_config
std
::
string
to_string
(
stereo_config_type
stereo_config
);
/// @brief return the @ref stereo_config_type for the string representation @a stereo_config
stereo_config_type
parse_stereo_config_from_string
(
const
std
::
string
&
stereo_config
);
/// --------------------------------------------------------------------
/// \brief struct containing information about an atom in a chemical compound.
/// This is a subset of the available information. Contact the author if you need more fields.
...
...
include/cif++/condition.hpp
View file @
821895bb
...
...
@@ -34,14 +34,100 @@
#include <regex>
#include <utility>
/** \file condition.hpp
* This file contains code to create conditions: object encapsulating a
* query you can use to find rows in a @ref cif::category
*
* Conditions are created as standard C++ expressions. That means
* you can use the standard comparison operators to compare field
* contents with a value and boolean operators to chain everything
* together.
*
* To create a query that simply compares one field with one value:
*
* @code {.cpp}
* cif::condition c = cif::key("id") == 1;
* @endcode
*
* That will find rows where the ID field contains the number 1. If
* using cif::key is a bit too much typing, you can also write:
*
* @code{.cpp}
* using namespace cif::literals;
*
* cif::condition c2 = "id"_key == 1;
* @endcode
*
* Now if you want both ID = 1 and ID = 2 in the result:
*
* @code{.cpp}
* auto c3 = "id"_key == 1 or "id"_key == 2;
* @endcode
*
* There are some special values you can use. To find rows with field that
* do not have a value:
*
* @code{.cpp}
* auto c4 = "type"_key == cif::null;
* @endcode
*
* Of if it should not be NULL:
*
* @code{.cpp}
* auto c5 = "type"_key != cif::null;
* @endcode
*
* There's even a way to find all records:
*
* @code{.cpp}
* auto c6 = cif::all;
* @endcode
*
* And when you want to search for any column containing the value 'foo':
*
* @code{.cpp}
* auto c7 = cif::any == "foo";
* @endcode
*
* All these conditions can be chained together again:
*
* @code{.cpp}
* auto c8 = std::move(c3) and std::move(c5);
* @endcode
*/
namespace
cif
{
// --------------------------------------------------------------------
// let's make life easier
/// let's make life easier, since @ref cif::category is not known yet,
/// we declare a function to access its contents
/**
* @brief Get the fields that can be used as key in conditions for a category
*
* @param cat The category whose fields to return
* @return iset The set of key field names
*/
iset
get_category_fields
(
const
category
&
cat
);
/**
* @brief Get the column index for column @a col in category @a cat
*
* @param cat The category
* @param col The name of the column
* @return uint16_t The index
*/
uint16_t
get_column_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*
*
* @param cat The category
* @param col The column name
* @return true If the primitive type is of type *uchar*
* @return false If the primitive type is not of type *uchar*
*/
bool
is_column_type_uchar
(
const
category
&
cat
,
std
::
string_view
col
);
// --------------------------------------------------------------------
...
...
@@ -72,16 +158,29 @@ namespace detail
struct
not_condition_impl
;
}
// namespace detail
/**
* @brief The interface class for conditions. This uses the bridge pattern,
* which means the implementation is in the member m_impl
*/
class
condition
{
public
:
using
condition_impl
=
detail
::
condition_impl
;
/**
* @brief Construct a new, empty condition object
*
*/
condition
()
:
m_impl
(
nullptr
)
{
}
/**
* @brief Construct a new condition object with implementation @a impl
*
* @param impl The implementation to use
*/
explicit
condition
(
condition_impl
*
impl
)
:
m_impl
(
impl
)
{
...
...
@@ -109,8 +208,22 @@ class condition
m_impl
=
nullptr
;
}
/**
* @brief Prepare the condition to be used on category @a c. This will
* take care of setting the correct indices for fields e.g.
*
* @param c The category this query should act upon
*/
void
prepare
(
const
category
&
c
);
/**
* @brief This operator returns true if the row referenced by @a r is
* a match for this condition.
*
* @param r The reference to a row.
* @return true If there is a match
* @return false If there is no match
*/
bool
operator
()(
row_handle
r
)
const
{
assert
(
this
->
m_impl
!=
nullptr
);
...
...
@@ -118,27 +231,53 @@ class condition
return
m_impl
?
m_impl
->
test
(
r
)
:
false
;
}
/**
* @brief Return true if the condition is not empty
*/
explicit
operator
bool
()
{
return
not
empty
();
}
/**
* @brief Return true if the condition is empty, has no condition
*/
bool
empty
()
const
{
return
m_impl
==
nullptr
;
}
/**
* @brief If the prepare step found out there is only one hit
* this single hit can be returned by this method.
*
* @return std::optional<row_handle> The result will contain
* a row reference if there is a single hit, it will be empty otherwise
*/
std
::
optional
<
row_handle
>
single
()
const
{
return
m_impl
?
m_impl
->
single
()
:
std
::
optional
<
row_handle
>
();
}
friend
condition
operator
||
(
condition
&&
a
,
condition
&&
b
);
friend
condition
operator
&&
(
condition
&&
a
,
condition
&&
b
);
friend
condition
operator
||
(
condition
&&
a
,
condition
&&
b
);
/**< Operator OR */
friend
condition
operator
&&
(
condition
&&
a
,
condition
&&
b
);
/**< Operator AND */
/// @cond
friend
struct
detail
::
or_condition_impl
;
friend
struct
detail
::
and_condition_impl
;
friend
struct
detail
::
not_condition_impl
;
/// @endcond
/**
* @brief Swap two conditions
*/
void
swap
(
condition
&
rhs
)
{
std
::
swap
(
m_impl
,
rhs
.
m_impl
);
std
::
swap
(
m_prepared
,
rhs
.
m_prepared
);
}
/**
* @brief Operator to use to write out a condition to @a os, for debugging purposes
*
* @param os The std::ostream to write to
* @param cond The condition to write
* @return std::ostream& The same as @a os
*/
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
condition
&
cond
)
{
if
(
cond
.
m_impl
)
...
...
@@ -691,6 +830,9 @@ namespace detail
}
// namespace detail
/**
* @brief Create a condition containing the logical AND of conditions @a a and @a b
*/
inline
condition
operator
and
(
condition
&&
a
,
condition
&&
b
)
{
if
(
a
.
m_impl
and
b
.
m_impl
)
...
...
@@ -700,6 +842,9 @@ inline condition operator and(condition &&a, condition &&b)
return
condition
(
std
::
move
(
b
));
}
/**
* @brief Create a condition containing the logical OR of conditions @a a and @a b
*/
inline
condition
operator
or
(
condition
&&
a
,
condition
&&
b
)
{
if
(
a
.
m_impl
and
b
.
m_impl
)
...
...
@@ -732,21 +877,49 @@ inline condition operator or(condition &&a, condition &&b)
return
condition
(
std
::
move
(
b
));
}
/**
* @brief A helper class to make it possible to search for empty fields (NULL)
*
* @code{.cpp}
* "id"_key == cif::empty_type();
* @endcode
*/
struct
empty_type
{
};
/// \brief A helper to make it possible to have conditions like ("id"_key == cif::null)
/**
* @brief A helper to make it possible to have conditions like
*
* @code{.cpp}
* "id"_key == cif::null;
* @endcode
*/
inline
constexpr
empty_type
null
=
empty_type
();
/**
* @brief Class to use in creating conditions, creates a reference to a field or column
*
*/
struct
key
{
/**
* @brief Construct a new key object using @a itemTag as name
*
* @param itemTag
*/
explicit
key
(
const
std
::
string
&
itemTag
)
:
m_item_tag
(
itemTag
)
{
}
/**
* @brief Construct a new key object using @a itemTag as name
*
* @param itemTag
*/
explicit
key
(
const
char
*
itemTag
)
:
m_item_tag
(
itemTag
)
{
...
...
@@ -755,44 +928,49 @@ struct key
key
(
const
key
&
)
=
delete
;
key
&
operator
=
(
const
key
&
)
=
delete
;
std
::
string
m_item_tag
;
std
::
string
m_item_tag
;
///< The column name
};
/**
* @brief Operator to create an equals condition based on a key @a key and a value @a v
*/
template
<
typename
T
>
condition
operator
==
(
const
key
&
key
,
const
T
&
v
)
{
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_tag
,
v
}));
}
inline
condition
operator
==
(
const
key
&
key
,
const
char
*
value
)
/**
* @brief Operator to create an equals condition based on a key @a key and a value @a value
*/
inline
condition
operator
==
(
const
key
&
key
,
std
::
string_view
value
)
{
if
(
value
!=
nullptr
and
*
value
!=
0
)
if
(
not
value
.
empty
()
)
return
condition
(
new
detail
::
key_equals_condition_impl
({
key
.
m_item_tag
,
value
}));
else
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_tag
));
}
// inline condition_t operator==(const key& key, const detail::ItemReference& v)
// {
// if (v.empty())
// return condition_t(new detail::key_is_empty_condition_impl(key.m_item_tag));
// else
// return condition_t(new detail::key_compare_condition_impl(key.m_item_tag, [tag = key.m_item_tag, v](const category& c, const row& r, bool icase)
// { return r[tag].template compare<(v, icase) == 0; }));
// }
/**
* @brief Operator to create a not equals condition based on a key @a key and a value @a v
*/
template
<
typename
T
>
condition
operator
!=
(
const
key
&
key
,
const
T
&
v
)
{
return
condition
(
new
detail
::
not_condition_impl
(
operator
==
(
key
,
v
)));
}
inline
condition
operator
!=
(
const
key
&
key
,
const
char
*
v
)
/**
* @brief Operator to create a not equals condition based on a key @a key and a value @a value
*/
inline
condition
operator
!=
(
const
key
&
key
,
std
::
string_view
value
)
{
std
::
string
value
(
v
?
v
:
""
);
return
condition
(
new
detail
::
not_condition_impl
(
operator
==
(
key
,
value
)));
}
/**
* @brief Operator to create a greater than condition based on a key @a key and a value @a v
*/
template
<
typename
T
>
condition
operator
>
(
const
key
&
key
,
const
T
&
v
)
{
...
...
@@ -805,6 +983,9 @@ condition operator>(const key &key, const T &v)
s
.
str
()));
}
/**
* @brief Operator to create a greater than or equals condition based on a key @a key and a value @a v
*/
template
<
typename
T
>
condition
operator
>=
(
const
key
&
key
,
const
T
&
v
)
{
...
...
@@ -817,6 +998,9 @@ condition operator>=(const key &key, const T &v)
s
.
str
()));
}
/**
* @brief Operator to create a less than condition based on a key @a key and a value @a v
*/
template
<
typename
T
>
condition
operator
<
(
const
key
&
key
,
const
T
&
v
)
{
...
...
@@ -829,6 +1013,9 @@ condition operator<(const key &key, const T &v)
s
.
str
()));
}
/**
* @brief Operator to create a less than or equals condition based on a key @a key and a value @a v
*/
template
<
typename
T
>
condition
operator
<=
(
const
key
&
key
,
const
T
&
v
)
{
...
...
@@ -841,43 +1028,69 @@ condition operator<=(const key &key, const T &v)
s
.
str
()));
}
/**
* @brief Operator to create a condition based on a key @a key and a regular expression @a rx
*/
inline
condition
operator
==
(
const
key
&
key
,
const
std
::
regex
&
rx
)
{
return
condition
(
new
detail
::
key_matches_condition_impl
(
key
.
m_item_tag
,
rx
));
}
/**
* @brief Operator to create a condition based on a key @a key which should be empty/null
*/
inline
condition
operator
==
(
const
key
&
key
,
const
empty_type
&
)
{
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_tag
));
}
/**
* @brief Operator to create a condition based on a key @a key which should be not empty/null
*/
inline
condition
operator
!=
(
const
key
&
key
,
const
empty_type
&
)
{
return
condition
(
new
detail
::
key_is_not_empty_condition_impl
(
key
.
m_item_tag
));
}
/**
* @brief Operator to create a boolean opposite of the condition in @a rhs
*/
inline
condition
operator
not
(
condition
&&
rhs
)
{
return
condition
(
new
detail
::
not_condition_impl
(
std
::
move
(
rhs
)));
}
/** @cond */
struct
any_type
{
};
/** @endcond */
/**
* @brief A helper for any field constructs
*/
inline
constexpr
any_type
any
=
any_type
{};
/**
* @brief Create a condition to search any column for a value @a v
*/
template
<
typename
T
>
condition
operator
==
(
const
any_type
&
,
const
T
&
v
)
{
return
condition
(
new
detail
::
any_is_condition_impl
<
T
>
(
v
));
}
/**
* @brief Create a condition to search any column for a regular expression @a rx
*/
inline
condition
operator
==
(
const
any_type
&
,
const
std
::
regex
&
rx
)
{
return
condition
(
new
detail
::
any_matches_condition_impl
(
rx
));
}
/**
* @brief Create a condition to return all rows
*/
inline
condition
all
()
{
return
condition
(
new
detail
::
all_condition_impl
());
...
...
@@ -885,6 +1098,13 @@ inline condition all()
namespace
literals
{
/**
* @brief Return a cif::key for the column name @a text
*
* @param text The name of the column
* @param length The length of @a text
* @return key The cif::key created
*/
inline
key
operator
""
_key
(
const
char
*
text
,
size_t
length
)
{
return
key
(
std
::
string
(
text
,
length
));
...
...
src/compound.cpp
View file @
821895bb
...
...
@@ -56,7 +56,7 @@ std::string to_string(bond_type bondType)
throw
std
::
invalid_argument
(
"Invalid bondType"
);
}
bond_type
from_string
(
const
std
::
string
&
bondType
)
bond_type
parse_bond_type_
from_string
(
const
std
::
string
&
bondType
)
{
if
(
cif
::
iequals
(
bondType
,
"sing"
))
return
bond_type
::
sing
;
...
...
@@ -77,6 +77,28 @@ bond_type from_string(const std::string &bondType)
throw
std
::
invalid_argument
(
"Invalid bondType: "
+
bondType
);
}
std
::
string
to_string
(
stereo_config_type
stereoConfig
)
{
switch
(
stereoConfig
)
{
case
stereo_config_type
:
:
N
:
return
"N"
;
case
stereo_config_type
:
:
R
:
return
"R"
;
case
stereo_config_type
:
:
S
:
return
"S"
;
}
throw
std
::
invalid_argument
(
"Invalid stereoConfig"
);
}
stereo_config_type
parse_stereo_config_from_string
(
const
std
::
string
&
stereoConfig
)
{
if
(
cif
::
iequals
(
stereoConfig
,
"N"
))
return
stereo_config_type
::
N
;
if
(
cif
::
iequals
(
stereoConfig
,
"R"
))
return
stereo_config_type
::
R
;
if
(
cif
::
iequals
(
stereoConfig
,
"S"
))
return
stereo_config_type
::
S
;
throw
std
::
invalid_argument
(
"Invalid stereoConfig: "
+
stereoConfig
);
}
// --------------------------------------------------------------------
// compound helper classes
...
...
@@ -126,11 +148,12 @@ compound::compound(cif::datablock &db)
for
(
auto
row
:
chemCompAtom
)
{
compound_atom
atom
;
std
::
string
type_symbol
;
cif
::
tie
(
atom
.
id
,
type_symbol
,
atom
.
charge
,
atom
.
aromatic
,
atom
.
leaving_atom
,
atom
.
stereo_config
,
atom
.
x
,
atom
.
y
,
atom
.
z
)
=
std
::
string
type_symbol
,
stereo_config
;
cif
::
tie
(
atom
.
id
,
type_symbol
,
atom
.
charge
,
atom
.
aromatic
,
atom
.
leaving_atom
,
stereo_config
,
atom
.
x
,
atom
.
y
,
atom
.
z
)
=
row
.
get
(
"atom_id"
,
"type_symbol"
,
"charge"
,
"pdbx_aromatic_flag"
,
"pdbx_leaving_atom_flag"
,
"pdbx_stereo_config"
,
"model_Cartn_x"
,
"model_Cartn_y"
,
"model_Cartn_z"
);
atom
.
type_symbol
=
atom_type_traits
(
type_symbol
).
type
();
atom
.
stereo_config
=
parse_stereo_config_from_string
(
stereo_config
);
m_atoms
.
push_back
(
std
::
move
(
atom
));
}
...
...
@@ -140,7 +163,7 @@ compound::compound(cif::datablock &db)
compound_bond
bond
;
std
::
string
valueOrder
;
cif
::
tie
(
bond
.
atom_id
[
0
],
bond
.
atom_id
[
1
],
valueOrder
,
bond
.
aromatic
,
bond
.
stereo_config
)
=
row
.
get
(
"atom_id_1"
,
"atom_id_2"
,
"value_order"
,
"pdbx_aromatic_flag"
,
"pdbx_stereo_config"
);
bond
.
type
=
from_string
(
valueOrder
);
bond
.
type
=
parse_bond_type_
from_string
(
valueOrder
);
m_bonds
.
push_back
(
std
::
move
(
bond
));
}
}
...
...
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