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
ab9c4d94
Unverified
Commit
ab9c4d94
authored
Aug 03, 2022
by
Maarten L. Hekkelman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
compiling again
parent
e5eb6225
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
1992 additions
and
1807 deletions
+1992
-1807
CMakeLists.txt
+4
-0
include/cif++/v2/category.hpp
+171
-368
include/cif++/v2/condition.hpp
+180
-216
include/cif++/v2/datablock.hpp
+58
-79
include/cif++/v2/file.hpp
+15
-37
include/cif++/v2/forward_decl.hpp
+15
-10
include/cif++/v2/item.hpp
+60
-54
include/cif++/v2/iterator.hpp
+182
-177
include/cif++/v2/parser.hpp
+24
-766
include/cif++/v2/row.hpp
+54
-57
include/cif++/v2/validate.hpp
+6
-7
src/v2/category.cpp
+283
-0
src/v2/dictionary_parser.cpp
+24
-22
src/v2/item.cpp
+43
-0
src/v2/parser.cpp
+814
-0
src/v2/row.cpp
+48
-0
src/v2/validate.cpp
+11
-14
No files found.
CMakeLists.txt
View file @
ab9c4d94
...
@@ -215,7 +215,11 @@ set(project_sources
...
@@ -215,7 +215,11 @@ set(project_sources
${
PROJECT_SOURCE_DIR
}
/src/Symmetry.cpp
${
PROJECT_SOURCE_DIR
}
/src/Symmetry.cpp
${
PROJECT_SOURCE_DIR
}
/src/TlsParser.cpp
${
PROJECT_SOURCE_DIR
}
/src/TlsParser.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/category.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/dictionary_parser.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/dictionary_parser.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/item.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/parser.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/row.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/validate.cpp
${
PROJECT_SOURCE_DIR
}
/src/v2/validate.cpp
)
)
...
...
include/cif++/v2/category.hpp
View file @
ab9c4d94
...
@@ -37,119 +37,38 @@ namespace cif::v2
...
@@ -37,119 +37,38 @@ namespace cif::v2
// --------------------------------------------------------------------
// --------------------------------------------------------------------
template
<
typename
Alloc
>
class
category
class
category_t
{
{
private
:
// --------------------------------------------------------------------
// Internal storage, strictly forward linked list with minimal space
// requirements. Strings of size 7 or shorter are stored internally.
// Typically, more than 99% of the strings in an mmCIF file are less
// than 8 bytes in length.
struct
item_value
{
item_value
(
uint16_t
column_ix
,
uint16_t
length
)
:
m_next
(
nullptr
)
,
m_column_ix
(
column_ix
)
,
m_length
(
length
)
{
}
item_value
()
=
delete
;
item_value
(
const
item_value
&
)
=
delete
;
item_value
&
operator
=
(
const
item_value
&
)
=
delete
;
item_value
*
m_next
;
uint16_t
m_column_ix
;
uint16_t
m_length
;
union
{
char
m_local_data
[
8
];
char
*
m_data
;
};
static
constexpr
size_t
kBufferSize
=
sizeof
(
m_local_data
);
std
::
string_view
text
()
const
{
return
{
m_length
>=
kBufferSize
?
m_data
:
m_local_data
,
m_length
};
}
const
char
*
c_str
()
const
{
return
m_length
>=
kBufferSize
?
m_data
:
m_local_data
;
}
};
static_assert
(
sizeof
(
item_value
)
==
24
,
"sizeof(item_value) should be 24 bytes"
);
public
:
public
:
using
allocator_type
=
Alloc
;
allocator_type
get_allocator
()
const
{
return
m_allocator
;
}
template
<
typename
>
friend
class
row_handle
;
friend
class
row_handle
;
template
<
typename
,
typename
...
>
template
<
typename
,
typename
...
>
friend
class
iterator_impl
;
friend
class
iterator_impl
;
using
value_type
=
row_handle
<
category_t
>
;
using
value_type
=
row_handle
;
using
reference
=
value_type
;
using
reference
=
value_type
;
using
const_reference
=
const
value_type
;
using
const_reference
=
const
value_type
;
using
iterator
=
iterator_impl
<
category_t
>
;
using
iterator
=
iterator_impl
<
category
>
;
using
const_iterator
=
iterator_impl
<
const
category_t
>
;
using
const_iterator
=
iterator_impl
<
const
category
>
;
class
row
{
public
:
row
()
=
default
;
private
:
template
<
typename
>
friend
class
item_handle
;
template
<
typename
,
typename
...
>
friend
class
iterator_impl
;
friend
class
category_
t
;
category
()
=
defaul
t
;
void
append
(
item_value
*
iv
)
category
(
std
::
string_view
name
)
{
:
m_name
(
name
)
if
(
m_head
==
nullptr
)
m_head
=
m_tail
=
iv
;
else
m_tail
=
m_tail
->
m_next
=
iv
;
}
row
*
m_next
=
nullptr
;
item_value
*
m_head
=
nullptr
,
*
m_tail
=
nullptr
;
};
category_t
()
=
default
;
category_t
(
std
::
string_view
name
,
const
allocator_type
&
alloc
=
allocator_type
())
:
m_allocator
(
alloc
)
,
m_name
(
name
)
{
{
}
}
category_t
(
const
category_t
&
rhs
)
category
(
const
category
&
rhs
)
:
m_allocator
(
std
::
allocator_traits
<
allocator_type
>::
select_on_container_copy_construction
(
rhs
.
get_allocator
()))
:
m_name
(
rhs
.
m_name
)
,
m_name
(
rhs
.
m_name
)
,
m_columns
(
rhs
.
m_columns
)
,
m_columns
(
rhs
.
m_columns
)
{
{
for
(
auto
r
=
rhs
.
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
for
(
auto
r
=
rhs
.
m_head
;
r
!=
nullptr
;
r
=
r
->
m_next
)
insert_impl
(
end
(),
clone_row
(
*
r
));
insert_impl
(
end
(),
clone_row
(
*
r
));
}
}
category_t
(
category_t
&&
rhs
)
category
(
category
&&
rhs
)
:
m_allocator
(
std
::
move
(
rhs
.
m_allocator
))
:
m_name
(
std
::
move
(
rhs
.
m_name
))
,
m_name
(
std
::
move
(
rhs
.
m_name
))
,
m_columns
(
std
::
move
(
rhs
.
m_columns
))
,
m_columns
(
std
::
move
(
rhs
.
m_columns
))
,
m_head
(
rhs
.
m_head
)
,
m_head
(
rhs
.
m_head
)
,
m_tail
(
rhs
.
m_tail
)
,
m_tail
(
rhs
.
m_tail
)
...
@@ -158,28 +77,13 @@ class category_t
...
@@ -158,28 +77,13 @@ class category_t
rhs
.
m_tail
=
nullptr
;
rhs
.
m_tail
=
nullptr
;
}
}
template
<
typename
Alloc2
>
category
&
operator
=
(
const
category
&
rhs
)
category_t
(
const
category_t
&
c
,
const
Alloc2
&
a
)
:
m_allocator
(
a
)
,
m_name
(
c
.
m_name
)
{
}
template
<
typename
Alloc2
>
category_t
(
category_t
&&
c
,
const
Alloc2
&
a
)
:
m_allocator
(
a
)
,
m_name
(
std
::
move
(
c
.
m_name
))
{
}
category_t
&
operator
=
(
const
category_t
&
rhs
)
{
{
if
(
this
!=
&
rhs
)
if
(
this
!=
&
rhs
)
{
{
if
(
not
empty
())
if
(
not
empty
())
clear
();
clear
();
m_allocator
=
std
::
allocator_traits
<
allocator_type
>::
select_on_container_copy_construction
(
rhs
.
get_allocator
());
m_name
=
rhs
.
m_name
;
m_name
=
rhs
.
m_name
;
m_columns
=
rhs
.
m_columns
;
m_columns
=
rhs
.
m_columns
;
...
@@ -190,14 +94,13 @@ class category_t
...
@@ -190,14 +94,13 @@ class category_t
return
*
this
;
return
*
this
;
}
}
category
_t
&
operator
=
(
category_t
&&
rhs
)
category
&
operator
=
(
category
&&
rhs
)
{
{
if
(
this
!=
&
rhs
)
if
(
this
!=
&
rhs
)
{
{
if
(
not
empty
())
if
(
not
empty
())
clear
();
clear
();
m_allocator
=
std
::
move
(
rhs
.
m_allocator
);
m_name
=
std
::
move
(
rhs
.
m_name
);
m_name
=
std
::
move
(
rhs
.
m_name
);
m_columns
=
std
::
move
(
rhs
.
m_columns
);
m_columns
=
std
::
move
(
rhs
.
m_columns
);
...
@@ -210,7 +113,7 @@ class category_t
...
@@ -210,7 +113,7 @@ class category_t
return
*
this
;
return
*
this
;
}
}
~
category
_t
()
~
category
()
{
{
clear
();
clear
();
}
}
...
@@ -226,7 +129,7 @@ class category_t
...
@@ -226,7 +129,7 @@ class category_t
const_reference
front
()
const
const_reference
front
()
const
{
{
return
{
*
this
,
*
m_head
};
return
{
const_cast
<
category
&>
(
*
this
),
const_cast
<
row
&>
(
*
m_head
)
};
}
}
reference
back
()
reference
back
()
...
@@ -236,7 +139,7 @@ class category_t
...
@@ -236,7 +139,7 @@ class category_t
const_reference
back
()
const
const_reference
back
()
const
{
{
return
{
*
this
,
*
m_tail
};
return
{
const_cast
<
category
&>
(
*
this
),
const_cast
<
row
&>
(
*
m_tail
)
};
}
}
iterator
begin
()
iterator
begin
()
...
@@ -282,31 +185,165 @@ class category_t
...
@@ -282,31 +185,165 @@ class category_t
// --------------------------------------------------------------------
// --------------------------------------------------------------------
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
const
category_t
,
Ts
...
>
rows
(
Ns
...
names
)
const
iterator_proxy
<
const
category
,
Ts
...
>
rows
(
Ns
...
names
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
return
iterator_proxy
<
const
category
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...});
}
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
category
,
Ts
...
>
rows
(
Ns
...
names
)
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
return
iterator_proxy
<
category
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...});
}
// --------------------------------------------------------------------
conditional_iterator_proxy
<
category
>
find
(
condition
&&
cond
)
{
return
find
(
begin
(),
std
::
forward
<
condition
>
(
cond
));
}
conditional_iterator_proxy
<
category
>
find
(
iterator
pos
,
condition
&&
cond
)
{
return
{
*
this
,
pos
,
std
::
forward
<
condition
>
(
cond
)};
}
conditional_iterator_proxy
<
const
category
>
find
(
condition
&&
cond
)
const
{
return
find
(
cbegin
(),
std
::
forward
<
condition
>
(
cond
));
}
conditional_iterator_proxy
<
const
category
>
find
(
const_iterator
pos
,
condition
&&
cond
)
const
{
return
conditional_iterator_proxy
<
const
category
>
{
*
this
,
pos
,
std
::
forward
<
condition
>
(
cond
)};
}
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
category
,
Ts
...
>
find
(
condition
&&
cond
,
Ns
...
names
)
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
return
find
<
Ts
...
>
(
cbegin
(),
std
::
forward
<
condition
>
(
cond
),
std
::
forward
<
Ns
>
(
names
)...);
}
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
const
category
,
Ts
...
>
find
(
condition
&&
cond
,
Ns
...
names
)
const
{
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
return
iterator_proxy
<
const
category_t
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...}
);
return
find
<
Ts
...
>
(
cbegin
(),
std
::
forward
<
condition
>
(
cond
),
std
::
forward
<
Ns
>
(
names
)...
);
}
}
template
<
typename
...
Ts
,
typename
...
Ns
>
template
<
typename
...
Ts
,
typename
...
Ns
>
iterator_proxy
<
category_t
,
Ts
...
>
rows
(
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 titles should be equal to the number of types to return"
);
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
return
iterator_proxy
<
category_t
,
Ts
...
>
(
*
this
,
begin
(),
{
names
...});
return
{
*
this
,
pos
,
std
::
forward
<
condition
>
(
cond
),
std
::
forward
<
Ns
>
(
names
)...};
}
template
<
typename
...
Ts
,
typename
...
Ns
>
conditional_iterator_proxy
<
const
category
,
Ts
...
>
find
(
const_iterator
pos
,
condition
&&
cond
,
Ns
...
names
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Ns
),
"The number of column titles should be equal to the number of types to return"
);
return
{
*
this
,
pos
,
std
::
forward
<
condition
>
(
cond
),
std
::
forward
<
Ns
>
(
names
)...};
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// if you only expect a single row
row_handle
find1
(
condition
&&
cond
)
{
return
find1
(
begin
(),
std
::
forward
<
condition
>
(
cond
));
}
row_handle
find1
(
iterator
pos
,
condition
&&
cond
)
{
auto
h
=
find
(
pos
,
std
::
forward
<
condition
>
(
cond
));
void
insert
(
const_iterator
pos
,
const
row
&
row
)
if
(
h
.
empty
())
throw
std
::
runtime_error
(
"No hits found"
);
if
(
h
.
size
()
!=
1
)
throw
std
::
runtime_error
(
"Hit not unique"
);
return
*
h
.
begin
();
}
const
row_handle
find1
(
condition
&&
cond
)
const
{
return
find1
(
cbegin
(),
std
::
forward
<
condition
>
(
cond
));
}
const
row_handle
find1
(
const_iterator
pos
,
condition
&&
cond
)
const
{
auto
h
=
find
(
pos
,
std
::
forward
<
condition
>
(
cond
));
if
(
h
.
empty
())
throw
std
::
runtime_error
(
"No hits found"
);
if
(
h
.
size
()
!=
1
)
throw
std
::
runtime_error
(
"Hit not unique"
);
return
*
h
.
begin
();
}
template
<
typename
T
>
T
find1
(
condition
&&
cond
,
const
char
*
column
)
const
{
{
insert_impl
(
pos
,
row
);
return
find1
<
T
>
(
cbegin
(),
std
::
forward
<
condition
>
(
cond
),
column
);
}
}
void
insert
(
const_iterator
pos
,
row
&&
row
)
template
<
typename
T
>
T
find1
(
const_iterator
pos
,
condition
&&
cond
,
const
char
*
column
)
const
{
{
insert_impl
(
pos
,
std
::
move
(
row
));
auto
h
=
find
<
T
>
(
pos
,
std
::
forward
<
condition
>
(
cond
),
column
);
if
(
h
.
empty
())
throw
std
::
runtime_error
(
"No hits found"
);
if
(
h
.
size
()
!=
1
)
throw
std
::
runtime_error
(
"Hit not unique"
);
return
std
::
get
<
0
>
(
*
h
.
begin
());
}
}
template
<
typename
...
Ts
,
typename
...
Cs
,
typename
U
=
std
::
enable_if_t
<
sizeof
...(
Ts
)
!=
1
>>
std
::
tuple
<
Ts
...
>
find1
(
condition
&&
cond
,
Cs
...
columns
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of column titles should be equal to the number of types to return"
);
// static_assert(std::is_same_v<Cs, const char*>..., "The column names should be const char");
return
find1
<
Ts
...
>
(
cbegin
(),
std
::
forward
<
condition
>
(
cond
),
std
::
forward
<
Cs
>
(
columns
)...);
}
template
<
typename
...
Ts
,
typename
...
Cs
,
typename
U
=
std
::
enable_if_t
<
sizeof
...(
Ts
)
!=
1
>>
std
::
tuple
<
Ts
...
>
find1
(
const_iterator
pos
,
condition
&&
cond
,
Cs
...
columns
)
const
{
static_assert
(
sizeof
...(
Ts
)
==
sizeof
...(
Cs
),
"The number of column titles should be equal to the number of types to return"
);
auto
h
=
find
<
Ts
...
>
(
pos
,
std
::
forward
<
condition
>
(
cond
),
std
::
forward
<
Cs
>
(
columns
)...);
if
(
h
.
empty
())
throw
std
::
runtime_error
(
"No hits found"
);
if
(
h
.
size
()
!=
1
)
throw
std
::
runtime_error
(
"Hit not unique"
);
return
*
h
.
begin
();
}
bool
exists
(
condition
&&
cond
)
const
;
// --------------------------------------------------------------------
// void insert(const_iterator pos, const row &row)
// {
// insert_impl(pos, row);
// }
// void insert(const_iterator pos, row &&row)
// {
// insert_impl(pos, std::move(row));
// }
iterator
emplace
(
std
::
initializer_list
<
item
>
items
)
iterator
emplace
(
std
::
initializer_list
<
item
>
items
)
{
{
return
this
->
emplace
(
items
.
begin
(),
items
.
end
());
return
this
->
emplace
(
items
.
begin
(),
items
.
end
());
...
@@ -337,7 +374,7 @@ class category_t
...
@@ -337,7 +374,7 @@ class category_t
// }
// }
// if (not seen and iv->mMandatory)
// if (not seen and iv->mMandatory)
// throw std::runtime_error("missing mandatory field " + col.mName + " for
C
ategory " + mName);
// throw std::runtime_error("missing mandatory field " + col.mName + " for
c
ategory " + mName);
// }
// }
// if (mIndex != nullptr)
// if (mIndex != nullptr)
...
@@ -438,7 +475,7 @@ class category_t
...
@@ -438,7 +475,7 @@ class category_t
// {
// {
// item_validator = mCatValidator->getValidatorForItem(column_name);
// item_validator = mCatValidator->getValidatorForItem(column_name);
// if (item_validator == nullptr)
// if (item_validator == nullptr)
// m_validator->reportError("tag " + std::string(column_name) + " not allowed in
C
ategory " + mName, false);
// m_validator->reportError("tag " + std::string(column_name) + " not allowed in
c
ategory " + mName, false);
// }
// }
m_columns
.
emplace_back
(
column_name
,
item_validator
);
m_columns
.
emplace_back
(
column_name
,
item_validator
);
...
@@ -448,177 +485,20 @@ class category_t
...
@@ -448,177 +485,20 @@ class category_t
}
}
private
:
private
:
void
update_value
(
row
*
row
,
size_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
)
void
update_value
(
row
*
row
,
size_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
{
auto
&
col
=
m_columns
[
column
];
const
char
*
oldValue
=
nullptr
;
for
(
auto
iv
=
row
->
m_head
;
iv
!=
nullptr
;
iv
=
iv
->
m_next
)
{
assert
(
iv
!=
iv
->
m_next
and
(
iv
->
m_next
==
nullptr
or
iv
!=
iv
->
m_next
->
m_next
));
if
(
iv
->
m_column_ix
==
column
)
{
oldValue
=
iv
->
c_str
();
break
;
}
}
if
(
oldValue
!=
nullptr
and
value
==
oldValue
)
// no need to update
return
;
std
::
string
oldStrValue
=
oldValue
?
oldValue
:
""
;
// // check the value
// if (col.m_validator and validate)
// (*col.m_validator)(value);
// If the field is part of the Key for this Category, remove it from the index
// before updating
bool
reinsert
=
false
;
// if (updateLinked and // an update of an Item's value
// cat->mIndex != nullptr and cat->keyFieldsByIndex().count(column))
// {
// reinsert = cat->mIndex->find(mData);
// if (reinsert)
// cat->mIndex->erase(mData);
// }
// first remove old value with cix
if
(
row
->
m_head
==
nullptr
)
;
// nothing to do
else
if
(
row
->
m_head
->
m_column_ix
==
column
)
{
auto
iv
=
row
->
m_head
;
row
->
m_head
=
iv
->
m_next
;
iv
->
m_next
=
nullptr
;
delete_item
(
iv
);
}
else
{
for
(
auto
iv
=
row
->
m_head
;
iv
->
m_next
!=
nullptr
;
iv
=
iv
->
m_next
)
{
if
(
iv
->
m_next
->
m_column_ix
!=
column
)
continue
;
auto
nv
=
iv
->
m_next
;
iv
->
m_next
=
nv
->
m_next
;
nv
->
m_next
=
nullptr
;
delete_item
(
nv
);
break
;
}
}
if
(
not
value
.
empty
())
{
auto
nv
=
create_item
(
column
,
value
);
if
(
row
->
m_head
==
nullptr
)
row
->
m_head
=
nv
;
else
{
auto
iv
=
row
->
m_head
;
while
(
iv
->
m_next
!=
nullptr
)
iv
=
iv
->
m_next
;
iv
->
m_next
=
nv
;
}
}
// if (reinsert)
// cat->mIndex->insert(mData);
// // see if we need to update any child categories that depend on this value
// auto iv = col.m_validator;
// if (not skipUpdateLinked and iv != nullptr and mCascade)
// {
// for (auto &&[childCat, linked] : cat->mChildLinks)
// {
// if (find(linked->mParentKeys.begin(), linked->mParentKeys.end(), iv->mTag) == linked->mParentKeys.end())
// continue;
// Condition cond;
// std::string childTag;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// {
// childTag = ck;
// cond = std::move(cond) && Key(ck) == oldStrValue;
// }
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond = std::move(cond) && Key(ck) == Empty();
// else
// cond = std::move(cond) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows = childCat->find(std::move(cond));
// if (rows.empty())
// continue;
// // if (cif::VERBOSE > 2)
// // {
// // std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::endl
// // << cond << std::endl;
// // }
// // Now, suppose there are already rows in child that conform to the new value,
// // we then skip this renam
// Condition cond_n;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// cond_n = std::move(cond_n) && Key(ck) == value;
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond_n = std::move(cond_n) && Key(ck) == Empty();
// else
// cond_n = std::move(cond_n) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows_n = childCat->find(std::move(cond_n));
private
:
// if (not rows_n.empty())
using
allocator_type
=
std
::
allocator
<
void
>
;
// {
// if (cif::VERBOSE > 0)
// std::cerr << "Will not rename in child category since there are already rows that link to the parent" << std::endl;
// continue;
// }
// for (auto &cr : rows)
constexpr
allocator_type
get_allocator
()
const
// cr.assign(childTag, value, false);
{
// }
return
{};
// }
}
}
private
:
using
char_allocator_type
=
typename
std
::
allocator_traits
<
allocator_type
>::
template
rebind_alloc
<
char
>
;
using
char_allocator_type
=
typename
std
::
allocator_traits
<
Alloc
>::
template
rebind_alloc
<
char
>
;
using
char_allocator_traits
=
std
::
allocator_traits
<
char_allocator_type
>
;
using
char_allocator_traits
=
std
::
allocator_traits
<
char_allocator_type
>
;
using
item_allocator_type
=
typename
std
::
allocator_traits
<
Alloc
>::
template
rebind_alloc
<
item_value
>
;
using
item_allocator_type
=
typename
std
::
allocator_traits
<
allocator_type
>::
template
rebind_alloc
<
item_value
>
;
using
item_allocator_traits
=
std
::
allocator_traits
<
item_allocator_type
>
;
using
item_allocator_traits
=
std
::
allocator_traits
<
item_allocator_type
>
;
item_allocator_traits
::
pointer
get_item
()
item_allocator_traits
::
pointer
get_item
()
...
@@ -740,89 +620,13 @@ class category_t
...
@@ -740,89 +620,13 @@ class category_t
};
};
// proxy methods for every insertion
// proxy methods for every insertion
iterator
insert_impl
(
const_iterator
pos
,
row
*
n
)
iterator
insert_impl
(
const_iterator
pos
,
row
*
n
);
{
assert
(
n
!=
nullptr
);
assert
(
n
->
m_next
==
nullptr
);
if
(
n
==
nullptr
)
throw
std
::
runtime_error
(
"Invalid pointer passed to insert"
);
// insert at end, most often this is the case
if
(
pos
.
m_current
==
nullptr
)
{
if
(
m_head
==
nullptr
)
m_tail
=
m_head
=
n
;
else
m_tail
=
m_tail
->
m_next
=
n
;
}
else
{
assert
(
m_head
!=
nullptr
);
if
(
pos
.
m_current
==
m_head
)
m_head
=
n
->
m_next
=
m_head
;
else
n
=
n
->
m_next
=
m_head
->
m_next
;
}
return
iterator
(
*
this
,
n
);
}
iterator
erase_impl
(
const_iterator
pos
)
{
if
(
pos
==
cend
())
return
pos
;
row
*
n
=
const_cast
<
row
*>
(
&*
pos
);
row
*
cur
;
if
(
m_head
==
n
)
{
m_head
=
static_cast
<
row
*>
(
m_head
->
m_next
);
if
(
m_head
!=
nullptr
)
m_head
->
m_prev
=
nullptr
;
else
m_tail
=
nullptr
;
n
->
m_next
=
n
->
m_prev
=
n
->
m_parent
=
nullptr
;
delete_row
(
n
);
cur
=
m_head
;
iterator
erase_impl
(
const_iterator
pos
);
}
else
{
cur
=
static_cast
<
row
*>
(
n
->
m_next
);
if
(
m_tail
==
n
)
m_tail
=
static_cast
<
row
*>
(
n
->
m_prev
);
row
*
p
=
m_head
;
while
(
p
!=
nullptr
and
p
->
m_next
!=
n
)
p
=
p
->
m_next
;
if
(
p
!=
nullptr
and
p
->
m_next
==
n
)
{
p
->
m_next
=
n
->
m_next
;
if
(
p
->
m_next
!=
nullptr
)
p
->
m_next
->
m_prev
=
p
;
n
->
m_next
=
nullptr
;
}
else
throw
std
::
runtime_error
(
"remove for a row not found in the list"
);
delete_row
(
n
);
}
return
iterator
(
*
this
,
cur
);
}
allocator_type
m_allocator
;
std
::
string
m_name
;
std
::
string
m_name
;
std
::
vector
<
item_column
,
typename
std
::
allocator_traits
<
allocator_type
>::
template
rebind_alloc
<
item_column
>
>
m_columns
;
std
::
vector
<
item_column
>
m_columns
;
row
*
m_head
=
nullptr
,
*
m_tail
=
nullptr
;
row
*
m_head
=
nullptr
,
*
m_tail
=
nullptr
;
};
};
using
category
=
category_t
<>
;
}
//
namespace
cif
::
v2
}
//
namespace
cif
::
v2
\ No newline at end of file
include/cif++/v2/condition.hpp
View file @
ab9c4d94
...
@@ -41,145 +41,120 @@ namespace cif::v2
...
@@ -41,145 +41,120 @@ namespace cif::v2
namespace
detail
namespace
detail
{
{
template
<
typename
Category
>
struct
condition_impl
struct
condition_impl
{
{
using
category_type
=
Category
;
using
row_type
=
row_handle
<
category_type
>
;
virtual
~
condition_impl
()
{}
virtual
~
condition_impl
()
{}
virtual
void
prepare
(
const
C
ategory
&
c
)
{}
virtual
void
prepare
(
const
c
ategory
&
c
)
{}
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
=
0
;
virtual
bool
test
(
row_handle
r
)
const
=
0
;
virtual
void
str
(
std
::
ostream
&
os
)
const
=
0
;
virtual
void
str
(
std
::
ostream
&
os
)
const
=
0
;
};
};
template
<
typename
Category
>
struct
all_condition_impl
:
public
condition_impl
struct
all_condition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
bool
test
(
row_handle
r
)
const
override
{
return
true
;
}
using
row_type
=
base_type
::
row_type
;
void
str
(
std
::
ostream
&
os
)
const
override
{
os
<<
"*"
;
}
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
{
return
true
;
}
virtual
void
str
(
std
::
ostream
&
os
)
const
{
os
<<
"*"
;
}
};
};
template
<
typename
>
struct
or_condition_impl
;
struct
or_condition_impl
;
template
<
typename
>
struct
and_condition_impl
;
struct
and_condition_impl
;
template
<
typename
>
struct
not_condition_impl
;
struct
not_condition_impl
;
}
// namespace detail
}
// namespace detail
template
<
typename
Category
>
class
condition
class
condition_t
{
{
public
:
public
:
using
category_type
=
Category
;
using
condition_impl
=
detail
::
condition_impl
;
using
condition_impl
=
detail
::
condition_impl
<
category_type
>
;
using
row_type
=
row_handle
<
category_type
>
;
condition
_t
()
condition
()
:
m_impl
(
nullptr
)
:
m_impl
(
nullptr
)
{
{
}
}
condition
_t
(
condition_impl
*
impl
)
condition
(
condition_impl
*
impl
)
:
m_impl
(
impl
)
:
m_impl
(
impl
)
{
{
}
}
condition
_t
(
const
condition_t
&
)
=
delete
;
condition
(
const
condition
&
)
=
delete
;
condition
_t
(
condition_t
&&
rhs
)
noexcept
condition
(
condition
&&
rhs
)
noexcept
:
m_impl
(
nullptr
)
:
m_impl
(
nullptr
)
{
{
std
::
swap
(
m_impl
,
rhs
.
m_impl
);
std
::
swap
(
m_impl
,
rhs
.
m_impl
);
}
}
condition
_t
&
operator
=
(
const
condition_t
&
)
=
delete
;
condition
&
operator
=
(
const
condition
&
)
=
delete
;
condition
_t
&
operator
=
(
condition_t
&&
rhs
)
noexcept
condition
&
operator
=
(
condition
&&
rhs
)
noexcept
{
{
std
::
swap
(
m_impl
,
rhs
.
m_impl
);
std
::
swap
(
m_impl
,
rhs
.
m_impl
);
return
*
this
;
return
*
this
;
}
}
~
condition
_t
()
~
condition
()
{
{
delete
m_impl
;
delete
m_impl
;
m_impl
=
nullptr
;
m_impl
=
nullptr
;
}
}
void
prepare
(
const
category
_type
&
c
)
void
prepare
(
const
category
&
c
)
{
{
if
(
m_impl
)
if
(
m_impl
)
m_impl
->
prepare
(
c
);
m_impl
->
prepare
(
c
);
m_prepared
=
true
;
m_prepared
=
true
;
}
}
bool
operator
()(
const
category_type
&
c
,
const
row_type
&
r
)
const
bool
operator
()(
row_handle
r
)
const
{
{
assert
(
this
->
m_impl
!=
nullptr
);
assert
(
this
->
m_impl
!=
nullptr
);
assert
(
this
->
m_prepared
);
assert
(
this
->
m_prepared
);
return
m_impl
?
m_impl
->
test
(
c
,
r
)
:
false
;
return
m_impl
?
m_impl
->
test
(
r
)
:
false
;
}
}
bool
empty
()
const
{
return
m_impl
==
nullptr
;
}
bool
empty
()
const
{
return
m_impl
==
nullptr
;
}
template
<
typename
C
>
friend
condition_t
operator
||
(
condition_t
<
C
>
&&
a
,
condition_t
<
C
>
&&
b
);
friend
condition
operator
||
(
condition
&&
a
,
condition
&&
b
);
template
<
typename
C
>
friend
condition_t
operator
&&
(
condition_t
<
C
>
&&
a
,
condition_t
<
C
>
&&
b
);
friend
condition
operator
&&
(
condition
&&
a
,
condition
&&
b
);
template
<
typename
>
friend
struct
detail
::
or_condition_impl
;
friend
struct
detail
::
or_condition_impl
;
template
<
typename
>
friend
struct
detail
::
and_condition_impl
;
friend
struct
detail
::
and_condition_impl
;
template
<
typename
>
friend
struct
detail
::
not_condition_impl
;
friend
struct
detail
::
not_condition_impl
;
void
swap
(
condition
_t
&
rhs
)
void
swap
(
condition
&
rhs
)
{
{
std
::
swap
(
m_impl
,
rhs
.
m_impl
);
std
::
swap
(
m_impl
,
rhs
.
m_impl
);
std
::
swap
(
m_prepared
,
rhs
.
m_prepared
);
std
::
swap
(
m_prepared
,
rhs
.
m_prepared
);
}
}
template
<
typename
C
>
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
condition_t
<
C
>
&
cond
);
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
condition
&
cond
)
{
if
(
cond
.
m_impl
)
cond
.
m_impl
->
str
(
os
);
return
os
;
}
private
:
private
:
condition_impl
*
m_impl
;
condition_impl
*
m_impl
;
bool
m_prepared
=
false
;
bool
m_prepared
=
false
;
};
};
template
<
typename
Category
>
inline
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
condition_t
<
Category
>
&
cond
)
{
if
(
cond
.
m_impl
)
cond
.
m_impl
->
str
(
os
);
return
os
;
}
namespace
detail
namespace
detail
{
{
struct
key_is_empty_condition_impl
:
public
condition_impl
template
<
typename
Category
>
struct
keyIsemptycondition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
key_is_empty_condition_impl
(
const
std
::
string
&
item_tag
)
using
row_type
=
base_type
::
row_type
;
keyIsemptycondition_impl
(
const
std
::
string
&
item_tag
)
:
m_item_tag
(
item_tag
)
:
m_item_tag
(
item_tag
)
{
{
}
}
v
irtual
void
prepare
(
const
Category
&
c
)
;
v
oid
prepare
(
const
category
&
c
)
override
;
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
bool
test
(
row_handle
r
)
const
override
{
{
return
r
[
m_item_ix
].
empty
();
return
r
[
m_item_ix
].
empty
();
}
}
v
irtual
void
str
(
std
::
ostream
&
os
)
const
v
oid
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
m_item_tag
<<
" IS NULL"
;
os
<<
m_item_tag
<<
" IS NULL"
;
}
}
...
@@ -188,61 +163,53 @@ namespace detail
...
@@ -188,61 +163,53 @@ namespace detail
size_t
m_item_ix
=
0
;
size_t
m_item_ix
=
0
;
};
};
template
<
typename
Category
>
struct
key_compare_condition_impl
:
public
condition_impl
struct
keyComparecondition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
using
row_type
=
base_type
::
row_type
;
template
<
typename
COMP
>
template
<
typename
COMP
>
key
Compare
condition_impl
(
const
std
::
string
&
item_tag
,
COMP
&&
comp
,
const
std
::
string
&
s
)
key
_compare_
condition_impl
(
const
std
::
string
&
item_tag
,
COMP
&&
comp
,
const
std
::
string
&
s
)
:
m_item_tag
(
item_tag
)
:
m_item_tag
(
item_tag
)
,
m_compare
(
std
::
move
(
comp
))
,
m_compare
(
std
::
move
(
comp
))
,
m
S
tr
(
s
)
,
m
_s
tr
(
s
)
{
{
}
}
v
irtual
void
prepare
(
const
Category
&
c
)
;
v
oid
prepare
(
const
category
&
c
)
override
;
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
bool
test
(
row_handle
r
)
const
override
{
{
return
m_compare
(
c
,
r
,
m_icase
);
return
m_compare
(
r
,
m_icase
);
}
}
v
irtual
void
str
(
std
::
ostream
&
os
)
const
v
oid
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
m_item_tag
<<
(
m_icase
?
"^ "
:
" "
)
<<
m
S
tr
;
os
<<
m_item_tag
<<
(
m_icase
?
"^ "
:
" "
)
<<
m
_s
tr
;
}
}
std
::
string
m_item_tag
;
std
::
string
m_item_tag
;
size_t
m_item_ix
=
0
;
size_t
m_item_ix
=
0
;
bool
m_icase
=
false
;
bool
m_icase
=
false
;
std
::
function
<
bool
(
const
Category
&
,
const
row_type
&
,
bool
)
>
m_compare
;
std
::
function
<
bool
(
row_handle
,
bool
)
>
m_compare
;
std
::
string
m
S
tr
;
std
::
string
m
_s
tr
;
};
};
template
<
typename
Category
>
struct
key_matches_condition_impl
:
public
condition_impl
struct
keyMatchescondition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
key_matches_condition_impl
(
const
std
::
string
&
item_tag
,
const
std
::
regex
&
rx
)
using
row_type
=
base_type
::
row_type
;
keyMatchescondition_impl
(
const
std
::
string
&
item_tag
,
const
std
::
regex
&
rx
)
:
m_item_tag
(
item_tag
)
:
m_item_tag
(
item_tag
)
,
m_item_ix
(
0
)
,
m_item_ix
(
0
)
,
mRx
(
rx
)
,
mRx
(
rx
)
{
{
}
}
v
irtual
void
prepare
(
const
Category
&
c
)
;
v
oid
prepare
(
const
category
&
c
)
override
;
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
bool
test
(
row_handle
r
)
const
override
{
{
std
::
string_view
txt
=
r
[
m_item_ix
].
text
();
std
::
string_view
txt
=
r
[
m_item_ix
].
text
();
return
std
::
regex_match
(
txt
.
begin
(),
txt
.
end
(),
mRx
);
return
std
::
regex_match
(
txt
.
begin
(),
txt
.
end
(),
mRx
);
}
}
v
irtual
void
str
(
std
::
ostream
&
os
)
const
v
oid
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
m_item_tag
<<
" =~ expression"
;
os
<<
m_item_tag
<<
" =~ expression"
;
}
}
...
@@ -252,21 +219,40 @@ namespace detail
...
@@ -252,21 +219,40 @@ namespace detail
std
::
regex
mRx
;
std
::
regex
mRx
;
};
};
template
<
typename
Category
,
typename
T
>
template
<
typename
T
>
struct
AnyIscondition_impl
:
public
condition_impl
<
Category
>
struct
any_is_condition_impl
:
public
condition_impl
{
{
using
base_type
=
condition_impl
<
Category
>
;
using
row_type
=
base_type
::
row_type
;
typedef
T
valueType
;
typedef
T
valueType
;
AnyIs
condition_impl
(
const
valueType
&
value
)
any_is_
condition_impl
(
const
valueType
&
value
)
:
mValue
(
value
)
:
mValue
(
value
)
{
{
}
}
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
;
bool
test
(
row_handle
r
)
const
override
virtual
void
str
(
std
::
ostream
&
os
)
const
{
auto
&
c
=
r
.
cat
();
bool
result
=
false
;
for
(
auto
&
f
:
get_category_fields
(
c
))
{
try
{
if
(
r
[
f
].
compare
(
mValue
)
==
0
)
{
result
=
true
;
break
;
}
}
catch
(...)
{
}
}
return
result
;
}
void
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
"<any> == "
<<
mValue
;
os
<<
"<any> == "
<<
mValue
;
}
}
...
@@ -274,19 +260,38 @@ namespace detail
...
@@ -274,19 +260,38 @@ namespace detail
valueType
mValue
;
valueType
mValue
;
};
};
template
<
typename
Category
>
struct
any_matches_condition_impl
:
public
condition_impl
struct
AnyMatchescondition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
any_matches_condition_impl
(
const
std
::
regex
&
rx
)
using
row_type
=
base_type
::
row_type
;
AnyMatchescondition_impl
(
const
std
::
regex
&
rx
)
:
mRx
(
rx
)
:
mRx
(
rx
)
{
{
}
}
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
;
bool
test
(
row_handle
r
)
const
override
virtual
void
str
(
std
::
ostream
&
os
)
const
{
auto
&
c
=
r
.
cat
();
bool
result
=
false
;
for
(
auto
&
f
:
get_category_fields
(
c
))
{
try
{
std
::
string_view
txt
=
r
[
f
].
text
();
if
(
std
::
regex_match
(
txt
.
begin
(),
txt
.
end
(),
mRx
))
{
result
=
true
;
break
;
}
}
catch
(...)
{
}
}
return
result
;
}
void
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
"<any> =~ expression"
;
os
<<
"<any> =~ expression"
;
}
}
...
@@ -294,13 +299,9 @@ namespace detail
...
@@ -294,13 +299,9 @@ namespace detail
std
::
regex
mRx
;
std
::
regex
mRx
;
};
};
template
<
typename
Category
>
struct
and_condition_impl
:
public
condition_impl
struct
and_condition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
and_condition_impl
(
condition
&&
a
,
condition
&&
b
)
using
row_type
=
base_type
::
row_type
;
and_condition_impl
(
condition_t
<
Category
>
&&
a
,
condition_t
<
Category
>
&&
b
)
:
mA
(
nullptr
)
:
mA
(
nullptr
)
,
mB
(
nullptr
)
,
mB
(
nullptr
)
{
{
...
@@ -314,18 +315,18 @@ namespace detail
...
@@ -314,18 +315,18 @@ namespace detail
delete
mB
;
delete
mB
;
}
}
v
irtual
void
prepare
(
const
Category
&
c
)
v
oid
prepare
(
const
category
&
c
)
override
{
{
mA
->
prepare
(
c
);
mA
->
prepare
(
c
);
mB
->
prepare
(
c
);
mB
->
prepare
(
c
);
}
}
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
bool
test
(
row_handle
r
)
const
override
{
{
return
mA
->
test
(
c
,
r
)
and
mB
->
test
(
c
,
r
);
return
mA
->
test
(
r
)
and
mB
->
test
(
r
);
}
}
v
irtual
void
str
(
std
::
ostream
&
os
)
const
v
oid
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
'('
;
os
<<
'('
;
mA
->
str
(
os
);
mA
->
str
(
os
);
...
@@ -334,17 +335,13 @@ namespace detail
...
@@ -334,17 +335,13 @@ namespace detail
os
<<
')'
;
os
<<
')'
;
}
}
base_type
*
mA
;
condition_impl
*
mA
;
base_type
*
mB
;
condition_impl
*
mB
;
};
};
template
<
typename
Category
>
struct
or_condition_impl
:
public
condition_impl
struct
or_condition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
or_condition_impl
(
condition
&&
a
,
condition
&&
b
)
using
row_type
=
base_type
::
row_type
;
or_condition_impl
(
condition_t
<
Category
>
&&
a
,
condition_t
<
Category
>
&&
b
)
:
mA
(
nullptr
)
:
mA
(
nullptr
)
,
mB
(
nullptr
)
,
mB
(
nullptr
)
{
{
...
@@ -358,18 +355,18 @@ namespace detail
...
@@ -358,18 +355,18 @@ namespace detail
delete
mB
;
delete
mB
;
}
}
v
irtual
void
prepare
(
const
Category
&
c
)
v
oid
prepare
(
const
category
&
c
)
override
{
{
mA
->
prepare
(
c
);
mA
->
prepare
(
c
);
mB
->
prepare
(
c
);
mB
->
prepare
(
c
);
}
}
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
bool
test
(
row_handle
r
)
const
override
{
{
return
mA
->
test
(
c
,
r
)
or
mB
->
test
(
c
,
r
);
return
mA
->
test
(
r
)
or
mB
->
test
(
r
);
}
}
v
irtual
void
str
(
std
::
ostream
&
os
)
const
v
oid
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
'('
;
os
<<
'('
;
mA
->
str
(
os
);
mA
->
str
(
os
);
...
@@ -378,17 +375,13 @@ namespace detail
...
@@ -378,17 +375,13 @@ namespace detail
os
<<
')'
;
os
<<
')'
;
}
}
base_type
*
mA
;
condition_impl
*
mA
;
base_type
*
mB
;
condition_impl
*
mB
;
};
};
template
<
typename
Category
>
struct
not_condition_impl
:
public
condition_impl
struct
not_condition_impl
:
public
condition_impl
<
Category
>
{
{
using
base_type
=
condition_impl
<
Category
>
;
not_condition_impl
(
condition
&&
a
)
using
row_type
=
base_type
::
row_type
;
not_condition_impl
(
condition_t
<
Category
>
&&
a
)
:
mA
(
nullptr
)
:
mA
(
nullptr
)
{
{
std
::
swap
(
mA
,
a
.
m_impl
);
std
::
swap
(
mA
,
a
.
m_impl
);
...
@@ -399,55 +392,53 @@ namespace detail
...
@@ -399,55 +392,53 @@ namespace detail
delete
mA
;
delete
mA
;
}
}
v
irtual
void
prepare
(
const
Category
&
c
)
v
oid
prepare
(
const
category
&
c
)
override
{
{
mA
->
prepare
(
c
);
mA
->
prepare
(
c
);
}
}
virtual
bool
test
(
const
Category
&
c
,
const
row_type
&
r
)
const
bool
test
(
row_handle
r
)
const
override
{
{
return
not
mA
->
test
(
c
,
r
);
return
not
mA
->
test
(
r
);
}
}
v
irtual
void
str
(
std
::
ostream
&
os
)
const
v
oid
str
(
std
::
ostream
&
os
)
const
override
{
{
os
<<
"NOT ("
;
os
<<
"NOT ("
;
mA
->
str
(
os
);
mA
->
str
(
os
);
os
<<
')'
;
os
<<
')'
;
}
}
base_type
*
mA
;
condition_impl
*
mA
;
};
};
}
// namespace detail
}
// namespace detail
template
<
typename
Category
>
inline
condition
operator
&&
(
condition
&&
a
,
condition
&&
b
)
inline
condition_t
<
Category
>
operator
&&
(
condition_t
<
Category
>
&&
a
,
condition_t
<
Category
>
&&
b
)
{
{
if
(
a
.
m_impl
and
b
.
m_impl
)
if
(
a
.
m_impl
and
b
.
m_impl
)
return
condition
_t
<
Category
>
(
new
detail
::
and_condition_impl
<
Category
>
(
std
::
move
(
a
),
std
::
move
(
b
)));
return
condition
(
new
detail
::
and_condition_impl
(
std
::
move
(
a
),
std
::
move
(
b
)));
if
(
a
.
m_impl
)
if
(
a
.
m_impl
)
return
condition
_t
<
Category
>
(
std
::
move
(
a
));
return
condition
(
std
::
move
(
a
));
return
condition
_t
<
Category
>
(
std
::
move
(
b
));
return
condition
(
std
::
move
(
b
));
}
}
template
<
typename
Category
>
inline
condition
operator
||
(
condition
&&
a
,
condition
&&
b
)
inline
condition_t
<
Category
>
operator
||
(
condition_t
<
Category
>
&&
a
,
condition_t
<
Category
>
&&
b
)
{
{
if
(
a
.
m_impl
and
b
.
m_impl
)
if
(
a
.
m_impl
and
b
.
m_impl
)
return
condition
_t
<
Category
>
(
new
detail
::
or_condition_impl
<
Category
>
(
std
::
move
(
a
),
std
::
move
(
b
)));
return
condition
(
new
detail
::
or_condition_impl
(
std
::
move
(
a
),
std
::
move
(
b
)));
if
(
a
.
m_impl
)
if
(
a
.
m_impl
)
return
condition
_t
<
Category
>
(
std
::
move
(
a
));
return
condition
(
std
::
move
(
a
));
return
condition
_t
<
Category
>
(
std
::
move
(
b
));
return
condition
(
std
::
move
(
b
));
}
}
struct
empty
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 ("id"_key == cif::null)
inline
constexpr
empty
null
=
empty
();
inline
constexpr
empty
_type
null
=
empty_type
();
struct
key
struct
key
{
{
...
@@ -467,161 +458,138 @@ struct key
...
@@ -467,161 +458,138 @@ struct key
std
::
string
m_item_tag
;
std
::
string
m_item_tag
;
};
};
template
<
typename
Category
,
typename
T
>
template
<
typename
T
>
condition
_t
<
Category
>
operator
==
(
const
key
&
key
,
const
T
&
v
)
condition
operator
==
(
const
key
&
key
,
const
T
&
v
)
{
{
using
category_type
=
Category
;
using
row_type
=
row_handle
<
category_type
>
;
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" == "
<<
v
;
s
<<
" == "
<<
v
;
return
condition
_t
<
Category
>
(
new
detail
::
keyComparecondition_impl
<
Category
>
(
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
Category
&
c
,
const
row_type
&
r
,
bool
icase
)
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
==
0
;
},
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
==
0
;
},
s
.
str
()));
s
.
str
()));
}
}
template
<
typename
Category
>
inline
condition
operator
==
(
const
key
&
key
,
const
char
*
value
)
inline
condition_t
<
Category
>
operator
==
(
const
key
&
key
,
const
char
*
value
)
{
{
using
category_type
=
Category
;
using
row_type
=
row_handle
<
category_type
>
;
if
(
value
!=
nullptr
and
*
value
!=
0
)
if
(
value
!=
nullptr
and
*
value
!=
0
)
{
{
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" == "
<<
value
;
s
<<
" == "
<<
value
;
return
condition
_t
<
Category
>
(
new
detail
::
keyComparecondition_impl
<
Category
>
(
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
value
](
const
Category
&
c
,
const
row_type
&
r
,
bool
icase
)
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
value
](
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
compare
(
value
,
icase
)
==
0
;
},
{
return
r
[
tag
].
compare
(
value
,
icase
)
==
0
;
},
s
.
str
()));
s
.
str
()));
}
}
else
else
return
condition
_t
(
new
detail
::
keyIsemptycondition_impl
<
Category
>
(
key
.
m_item_tag
));
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_tag
));
}
}
// inline condition_t operator==(const key& key, const detail::ItemReference& v)
// inline condition_t operator==(const key& key, const detail::ItemReference& v)
// {
// {
// if (v.empty())
// if (v.empty())
// return condition_t(new detail::key
Isempty
condition_impl(key.m_item_tag));
// return condition_t(new detail::key
_is_empty_
condition_impl(key.m_item_tag));
// else
// else
// return condition_t(new detail::key
Comparecondition_impl(key.m_item_tag, [tag = key.m_item_tag, v](const Category& c, const row_type
& r, bool icase)
// 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; }));
// { return r[tag].template compare<(v, icase) == 0; }));
// }
// }
template
<
typename
Category
,
typename
T
>
template
<
typename
T
>
condition
_t
<
Category
>
operator
!=
(
const
key
&
key
,
const
T
&
v
)
condition
operator
!=
(
const
key
&
key
,
const
T
&
v
)
{
{
return
condition
_t
<
Category
>
(
new
detail
::
not_condition_impl
<
Category
>
(
operator
==
(
key
,
v
)));
return
condition
(
new
detail
::
not_condition_impl
(
operator
==
(
key
,
v
)));
}
}
template
<
typename
Category
>
inline
condition
operator
!=
(
const
key
&
key
,
const
char
*
v
)
inline
condition_t
<
Category
>
operator
!=
(
const
key
&
key
,
const
char
*
v
)
{
{
std
::
string
value
(
v
?
v
:
""
);
std
::
string
value
(
v
?
v
:
""
);
return
condition
_t
<
Category
>
(
new
detail
::
not_condition_impl
<
Category
>
(
operator
==
(
key
,
value
)));
return
condition
(
new
detail
::
not_condition_impl
(
operator
==
(
key
,
value
)));
}
}
template
<
typename
Category
,
typename
T
>
template
<
typename
T
>
condition
_t
<
Category
>
operator
>
(
const
key
&
key
,
const
T
&
v
)
condition
operator
>
(
const
key
&
key
,
const
T
&
v
)
{
{
using
category_type
=
Category
;
using
row_type
=
row_handle
<
category_type
>
;
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" > "
<<
v
;
s
<<
" > "
<<
v
;
return
condition
_t
<
Category
>
(
new
detail
::
keyComparecondition_impl
<
Category
>
(
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
Category
&
c
,
const
row_type
&
r
,
bool
icase
)
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
category
&
c
,
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
},
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>
0
;
},
s
.
str
()));
s
.
str
()));
}
}
template
<
typename
Category
,
typename
T
>
template
<
typename
T
>
condition
_t
<
Category
>
operator
>=
(
const
key
&
key
,
const
T
&
v
)
condition
operator
>=
(
const
key
&
key
,
const
T
&
v
)
{
{
using
category_type
=
Category
;
using
row_type
=
row_handle
<
category_type
>
;
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" >= "
<<
v
;
s
<<
" >= "
<<
v
;
return
condition
_t
<
Category
>
(
new
detail
::
keyComparecondition_impl
<
Category
>
(
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
Category
&
c
,
const
row_type
&
r
,
bool
icase
)
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
category
&
c
,
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
},
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
>=
0
;
},
s
.
str
()));
s
.
str
()));
}
}
template
<
typename
Category
,
typename
T
>
template
<
typename
T
>
condition
_t
<
Category
>
operator
<
(
const
key
&
key
,
const
T
&
v
)
condition
operator
<
(
const
key
&
key
,
const
T
&
v
)
{
{
using
category_type
=
Category
;
using
row_type
=
row_handle
<
category_type
>
;
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" < "
<<
v
;
s
<<
" < "
<<
v
;
return
condition
_t
<
Category
>
(
new
detail
::
keyComparecondition_impl
<
Category
>
(
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
Category
&
c
,
const
row_type
&
r
,
bool
icase
)
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
category
&
c
,
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
},
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<
0
;
},
s
.
str
()));
s
.
str
()));
}
}
template
<
typename
Category
,
typename
T
>
template
<
typename
T
>
condition
_t
<
Category
>
operator
<=
(
const
key
&
key
,
const
T
&
v
)
condition
operator
<=
(
const
key
&
key
,
const
T
&
v
)
{
{
using
category_type
=
Category
;
using
row_type
=
row_handle
<
category_type
>
;
std
::
ostringstream
s
;
std
::
ostringstream
s
;
s
<<
" <= "
<<
v
;
s
<<
" <= "
<<
v
;
return
condition
_t
<
Category
>
(
new
detail
::
keyComparecondition_impl
<
Category
>
(
return
condition
(
new
detail
::
key_compare_condition_impl
(
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
Category
&
c
,
const
row_type
&
r
,
bool
icase
)
key
.
m_item_tag
,
[
tag
=
key
.
m_item_tag
,
v
](
const
category
&
c
,
row_handle
r
,
bool
icase
)
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
},
{
return
r
[
tag
].
template
compare
<
T
>
(
v
,
icase
)
<=
0
;
},
s
.
str
()));
s
.
str
()));
}
}
template
<
typename
Category
>
inline
condition
operator
==
(
const
key
&
key
,
const
std
::
regex
&
rx
)
inline
condition_t
<
Category
>
operator
==
(
const
key
&
key
,
const
std
::
regex
&
rx
)
{
{
return
condition
_t
<
Category
>
(
new
detail
::
keyMatchescondition_impl
<
Category
>
(
key
.
m_item_tag
,
rx
));
return
condition
(
new
detail
::
key_matches_condition_impl
(
key
.
m_item_tag
,
rx
));
}
}
template
<
typename
Category
>
inline
condition
operator
==
(
const
key
&
key
,
const
empty_type
&
)
inline
condition_t
<
Category
>
operator
==
(
const
key
&
key
,
const
empty
&
)
{
{
return
condition
_t
<
Category
>
(
new
detail
::
keyIsemptycondition_impl
<
Category
>
(
key
.
m_item_tag
));
return
condition
(
new
detail
::
key_is_empty_condition_impl
(
key
.
m_item_tag
));
}
}
template
<
typename
Category
>
struct
any_type
struct
any_t
{
{
};
};
template
<
typename
Category
,
typename
T
>
inline
constexpr
any_type
any
=
any_type
{};
condition_t
<
Category
>
operator
==
(
const
any_t
<
Category
>
&
,
const
T
&
v
)
template
<
typename
T
>
condition
operator
==
(
const
any_type
&
,
const
T
&
v
)
{
{
return
condition
_t
<
Category
>
(
new
detail
::
AnyIscondition_impl
<
Category
,
T
>
(
v
));
return
condition
(
new
detail
::
any_is_condition_impl
<
T
>
(
v
));
}
}
template
<
typename
Category
>
inline
condition
operator
==
(
const
any_type
&
,
const
std
::
regex
&
rx
)
condition_t
<
Category
>
operator
==
(
any_t
<
Category
>
&
,
const
std
::
regex
&
rx
)
{
{
return
condition
_t
<
Category
>
(
new
detail
::
AnyMatchescondition_impl
<
Category
>
(
rx
));
return
condition
(
new
detail
::
any_matches_condition_impl
(
rx
));
}
}
template
<
typename
Category
>
inline
condition
all
()
inline
condition_t
<
Category
>
all
()
{
{
return
condition
_t
<
Category
>
(
new
detail
::
all_condition_impl
<
Category
>
());
return
condition
(
new
detail
::
all_condition_impl
());
}
}
// inline condition_t<
Category> Not(condition_t<C
ategory> &&cond)
// inline condition_t<
category> Not(condition_t<c
ategory> &&cond)
// {
// {
// return condition_t<
Category>(new detail::not_condition_impl<Category>
(std::move(cond)));
// return condition_t<
category>(new detail::not_condition_impl
(std::move(cond)));
// }
// }
namespace
literals
namespace
literals
...
@@ -630,9 +598,6 @@ namespace literals
...
@@ -630,9 +598,6 @@ namespace literals
{
{
return
key
(
std
::
string
(
text
,
length
));
return
key
(
std
::
string
(
text
,
length
));
}
}
inline
constexpr
empty
null
=
empty
();
}
// namespace literals
}
// namespace literals
}
//
namespace
cif
::
v2
}
//
namespace
cif
::
v2
\ No newline at end of file
include/cif++/v2/datablock.hpp
View file @
ab9c4d94
...
@@ -35,47 +35,29 @@ namespace cif::v2
...
@@ -35,47 +35,29 @@ namespace cif::v2
// --------------------------------------------------------------------
// --------------------------------------------------------------------
template
<
typename
Alloc
,
typename
Category
>
class
datablock
class
datablock_t
{
{
public
:
public
:
using
category_type
=
Category
;
using
category_list
=
std
::
list
<
category
>
;
using
allocator_type
=
Alloc
;
using
category_allocator_type
=
typename
std
::
allocator_traits
<
Alloc
>::
template
rebind_alloc
<
category_type
>
;
using
iterator
=
category_list
::
iterator
;
using
c
ategory_type_list
=
std
::
list
<
category_type
,
category_allocator_type
>
;
using
c
onst_iterator
=
category_list
::
const_iterator
;
using
iterator
=
category_type_list
::
iterator
;
using
reference
=
typename
category_list
::
reference
;
using
const_iterator
=
category_type_list
::
const_iterator
;
using
reference
=
typename
category_type_list
::
reference
;
datablock
()
=
default
;
datablock_t
(
std
::
string_view
name
,
const
allocator_type
&
alloc
=
allocator_type
())
datablock
(
std
::
string_view
name
)
:
m_categories
(
alloc
)
:
m_name
(
name
)
,
m_name
(
name
)
{
{
}
}
datablock
_t
(
const
datablock_t
&
)
=
default
;
datablock
(
const
datablock
&
)
=
default
;
datablock
_t
(
datablock_t
&&
)
=
default
;
datablock
(
datablock
&&
)
=
default
;
// template <typename Alloc2>
datablock
&
operator
=
(
const
datablock
&
)
=
default
;
// datablock_t(const datablock_t &db, const Alloc2 &a)
datablock
&
operator
=
(
datablock
&&
)
=
default
;
// : m_categories(db, a)
// , m_name(db.m_name)
// {
// }
// template <typename Alloc2>
// datablock_t(datablock_t &&db, const Alloc2 &a)
// : base_type(std::move(db), a)
// , m_name(db.m_name)
// {
// }
datablock_t
&
operator
=
(
const
datablock_t
&
)
=
default
;
datablock_t
&
operator
=
(
datablock_t
&&
)
=
default
;
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -100,9 +82,9 @@ class datablock_t
...
@@ -100,9 +82,9 @@ class datablock_t
// --------------------------------------------------------------------
// --------------------------------------------------------------------
category
_type
&
operator
[](
std
::
string_view
name
)
category
&
operator
[](
std
::
string_view
name
)
{
{
auto
i
=
std
::
find_if
(
m_categories
.
begin
(),
m_categories
.
end
(),
[
name
](
const
category
_type
&
c
)
auto
i
=
std
::
find_if
(
m_categories
.
begin
(),
m_categories
.
end
(),
[
name
](
const
category
&
c
)
{
return
iequals
(
c
.
name
(),
name
);
});
{
return
iequals
(
c
.
name
(),
name
);
});
if
(
i
!=
m_categories
.
end
())
if
(
i
!=
m_categories
.
end
())
...
@@ -112,10 +94,10 @@ class datablock_t
...
@@ -112,10 +94,10 @@ class datablock_t
return
m_categories
.
back
();
return
m_categories
.
back
();
}
}
const
category
_type
&
operator
[](
std
::
string_view
name
)
const
const
category
&
operator
[](
std
::
string_view
name
)
const
{
{
static
const
category
_type
s_empty
;
static
const
category
s_empty
;
auto
i
=
std
::
find_if
(
m_categories
.
begin
(),
m_categories
.
end
(),
[
name
](
const
category
_type
&
c
)
auto
i
=
std
::
find_if
(
m_categories
.
begin
(),
m_categories
.
end
(),
[
name
](
const
category
&
c
)
{
return
iequals
(
c
.
name
(),
name
);
});
{
return
iequals
(
c
.
name
(),
name
);
});
return
i
==
m_categories
.
end
()
?
s_empty
:
*
i
;
return
i
==
m_categories
.
end
()
?
s_empty
:
*
i
;
}
}
...
@@ -155,53 +137,51 @@ class datablock_t
...
@@ -155,53 +137,51 @@ class datablock_t
return
std
::
make_tuple
(
m_categories
.
begin
(),
is_new
);
return
std
::
make_tuple
(
m_categories
.
begin
(),
is_new
);
}
}
void
write
(
std
::
ostream
&
os
)
const
//
void write(std::ostream &os) const
{
//
{
// std::shared_lock lock(mLock);
//
// std::shared_lock lock(mLock);
os
<<
"data_"
<<
m_name
<<
std
::
endl
//
os << "data_" << m_name << std::endl
<<
"# "
<<
std
::
endl
;
//
<< "# " << std::endl;
// mmcif support, sort of. First write the 'entry' Category
//
// mmcif support, sort of. First write the 'entry' Category
// and if it exists, _AND_ we have a Validator, write out the
//
// and if it exists, _AND_ we have a Validator, write out the
// audit_conform record.
//
// audit_conform record.
for
(
auto
&
cat
:
m_categories
)
//
for (auto &cat : m_categories)
{
//
{
if
(
cat
.
name
()
!=
"entry"
)
//
if (cat.name() != "entry")
continue
;
//
continue;
cat
.
write
(
os
);
//
cat.write(os);
// if (mValidator != nullptr)
//
// if (mValidator != nullptr)
// {
//
// {
// Category auditConform(*this, "audit_conform", nullptr);
//
// Category auditConform(*this, "audit_conform", nullptr);
// auditConform.emplace({{"dict_name", mValidator->dictName()},
//
// auditConform.emplace({{"dict_name", mValidator->dictName()},
// {"dict_version", mValidator->dictVersion()}});
//
// {"dict_version", mValidator->dictVersion()}});
// auditConform.write(os);
//
// auditConform.write(os);
// }
//
// }
break
;
//
break;
}
//
}
for
(
auto
&
cat
:
m_categories
)
//
for (auto &cat : m_categories)
{
//
{
if
(
cat
.
name
()
!=
"entry"
and
cat
.
name
()
!=
"audit_conform"
)
//
if (cat.name() != "entry" and cat.name() != "audit_conform")
cat
.
write
(
os
);
//
cat.write(os);
}
//
}
}
//
}
friend
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
datablock_t
&
db
)
// friend std::ostream &operator<<(std::ostream &os, const datablock
&db)
{
//
{
db
.
write
(
os
);
//
db.write(os);
return
os
;
//
return os;
}
//
}
private
:
private
:
category_
type_
list
m_categories
;
category_list
m_categories
;
std
::
string
m_name
;
std
::
string
m_name
;
};
};
using
datablock
=
datablock_t
<>
;
}
//
namespace
cif
::
v2
}
//
namespace
cif
::
v2
\ No newline at end of file
include/cif++/v2/file.hpp
View file @
ab9c4d94
...
@@ -36,20 +36,10 @@ namespace cif::v2
...
@@ -36,20 +36,10 @@ namespace cif::v2
// --------------------------------------------------------------------
// --------------------------------------------------------------------
template
<
class
file
typename
Alloc
,
typename
Datablock
,
typename
Category
>
class
file_t
{
{
public
:
public
:
using
allocator_type
=
Alloc
;
using
datablock_list
=
std
::
list
<
datablock
>
;
using
datablock_type
=
Datablock
;
using
category_type
=
typename
datablock_type
::
category_type
;
using
datablock_allocator_type
=
typename
std
::
allocator_traits
<
Alloc
>::
template
rebind_alloc
<
datablock_type
>
;
using
datablock_list
=
std
::
list
<
datablock_type
,
datablock_allocator_type
>
;
using
value_type
=
datablock_list
::
value_type
;
using
value_type
=
datablock_list
::
value_type
;
using
reference
=
datablock_list
::
reference
;
using
reference
=
datablock_list
::
reference
;
...
@@ -58,29 +48,21 @@ class file_t
...
@@ -58,29 +48,21 @@ class file_t
using
iterator
=
datablock_list
::
iterator
;
using
iterator
=
datablock_list
::
iterator
;
using
const_iterator
=
datablock_list
::
const_iterator
;
using
const_iterator
=
datablock_list
::
const_iterator
;
using
parser_type
=
parser_t
<
allocator_type
,
file_t
,
datablock_type
,
category_type
>
;
file
()
=
default
;
file_t
()
=
default
;
file_t
(
const
allocator_type
&
a
=
allocator_type
())
file
(
std
::
istream
&
is
)
:
m_datablocks
(
a
)
{
}
file_t
(
std
::
istream
&
is
,
const
allocator_type
&
alloc
=
allocator_type
())
:
m_datablocks
(
alloc
)
{
{
load
(
is
);
load
(
is
);
}
}
file
_t
(
const
file_t
&
)
=
default
;
file
(
const
file
&
)
=
default
;
file
_t
(
file_t
&&
)
=
default
;
file
(
file
&&
)
=
default
;
file
_t
&
operator
=
(
const
file_t
&
)
=
default
;
file
&
operator
=
(
const
file
&
)
=
default
;
file
_t
&
operator
=
(
file_t
&&
)
=
default
;
file
&
operator
=
(
file
&&
)
=
default
;
datablock
_type
&
operator
[](
std
::
string_view
name
)
datablock
&
operator
[](
std
::
string_view
name
)
{
{
auto
i
=
std
::
find_if
(
m_datablocks
.
begin
(),
m_datablocks
.
end
(),
[
name
](
const
datablock
_type
&
c
)
auto
i
=
std
::
find_if
(
m_datablocks
.
begin
(),
m_datablocks
.
end
(),
[
name
](
const
datablock
&
c
)
{
return
iequals
(
c
.
name
(),
name
);
});
{
return
iequals
(
c
.
name
(),
name
);
});
if
(
i
!=
m_datablocks
.
end
())
if
(
i
!=
m_datablocks
.
end
())
...
@@ -90,10 +72,10 @@ class file_t
...
@@ -90,10 +72,10 @@ class file_t
return
m_datablocks
.
back
();
return
m_datablocks
.
back
();
}
}
const
datablock
_type
&
operator
[](
std
::
string_view
name
)
const
const
datablock
&
operator
[](
std
::
string_view
name
)
const
{
{
static
const
datablock
_type
s_empty
;
static
const
datablock
s_empty
;
auto
i
=
std
::
find_if
(
m_datablocks
.
begin
(),
m_datablocks
.
end
(),
[
name
](
const
datablock
_type
&
c
)
auto
i
=
std
::
find_if
(
m_datablocks
.
begin
(),
m_datablocks
.
end
(),
[
name
](
const
datablock
&
c
)
{
return
iequals
(
c
.
name
(),
name
);
});
{
return
iequals
(
c
.
name
(),
name
);
});
return
i
==
m_datablocks
.
end
()
?
s_empty
:
*
i
;
return
i
==
m_datablocks
.
end
()
?
s_empty
:
*
i
;
}
}
...
@@ -133,14 +115,12 @@ class file_t
...
@@ -133,14 +115,12 @@ class file_t
reference
front
()
{
return
m_datablocks
.
front
();
}
reference
front
()
{
return
m_datablocks
.
front
();
}
reference
back
()
{
return
m_datablocks
.
back
();
}
reference
back
()
{
return
m_datablocks
.
back
();
}
void
load
(
std
::
istream
&
is
)
void
load
(
std
::
istream
&
is
)
{
{
// auto saved = mValidator;
// auto saved = mValidator;
// setValidator(nullptr);
// setValidator(nullptr);
parser
_type
p
(
is
,
*
this
);
parser
p
(
is
,
*
this
);
p
.
parse_file
();
p
.
parse_file
();
// if (saved != nullptr)
// if (saved != nullptr)
...
@@ -152,8 +132,7 @@ class file_t
...
@@ -152,8 +132,7 @@ class file_t
private
:
private
:
datablock_list
m_datablocks
;
datablock_list
m_datablocks
;
std
::
unique_ptr
<
Validator
>
m_validator
;
};
};
using
file
=
file_t
<>
;
}
}
\ No newline at end of file
include/cif++/v2/forward_decl.hpp
View file @
ab9c4d94
...
@@ -26,21 +26,27 @@
...
@@ -26,21 +26,27 @@
#pragma once
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace
cif
::
v2
namespace
cif
::
v2
{
{
template
<
typename
Alloc
=
std
::
allocator
<
void
>>
class
category
;
class
category_t
;
class
datablock
;
class
file
;
class
parser
;
template
<
typename
Alloc
=
std
::
allocator
<
void
>
,
typename
Category
=
category_t
<
Alloc
>>
class
row
;
class
datablock_t
;
class
row_handle
;
template
<
typename
Alloc
=
std
::
allocator
<
void
>
,
typename
Datablock
=
datablock_t
<
Alloc
>
,
typename
Category
=
typename
Datablock
::
category_type
>
class
item
;
class
file_t
;
class
item_handle
;
// --------------------------------------------------------------------
// let's make life easier
std
::
vector
<
std
::
string
>
get_category_fields
(
const
category
&
cat
);
template
<
typename
Alloc
=
std
::
allocator
<
void
>
,
typename
File
=
file_t
<
Alloc
>
,
typename
Datablock
=
datablock_t
<
Alloc
>
,
typename
Category
=
typename
Datablock
::
category_type
>
class
parser_t
;
}
//
namespace
cif
::
v2
}
//
namespace
cif
::
v2
\ No newline at end of file
include/cif++/v2/item.hpp
View file @
ab9c4d94
...
@@ -29,12 +29,15 @@
...
@@ -29,12 +29,15 @@
#include <charconv>
#include <charconv>
#include <cstring>
#include <cstring>
#include <iomanip>
#include <iomanip>
#include <iostream>
#include <limits>
#include <limits>
#include <memory>
#include <memory>
#include <optional>
#include <optional>
#include <cif++/CifUtils.hpp>
#include <cif++/CifUtils.hpp>
#include <cif++/v2/forward_decl.hpp>
namespace
cif
namespace
cif
{
{
extern
int
VERBOSE
;
extern
int
VERBOSE
;
...
@@ -80,7 +83,7 @@ class item
...
@@ -80,7 +83,7 @@ class item
auto
r
=
cif
::
to_chars
(
m_buffer
,
m_buffer
+
sizeof
(
m_buffer
)
-
1
,
value
,
cif
::
chars_format
::
general
);
auto
r
=
cif
::
to_chars
(
m_buffer
,
m_buffer
+
sizeof
(
m_buffer
)
-
1
,
value
,
cif
::
chars_format
::
general
);
if
(
r
.
ec
!=
std
::
errc
())
if
(
r
.
ec
!=
std
::
errc
())
throw
std
::
runtime_error
(
"Could not format number"
);
throw
std
::
runtime_error
(
"Could not format number"
);
assert
(
r
.
ptr
>=
m_buffer
and
r
.
ptr
<
m_buffer
+
sizeof
(
m_buffer
));
assert
(
r
.
ptr
>=
m_buffer
and
r
.
ptr
<
m_buffer
+
sizeof
(
m_buffer
));
*
r
.
ptr
=
0
;
*
r
.
ptr
=
0
;
m_value
=
std
::
string_view
(
m_buffer
,
r
.
ptr
-
m_buffer
);
m_value
=
std
::
string_view
(
m_buffer
,
r
.
ptr
-
m_buffer
);
...
@@ -138,13 +141,55 @@ class item
...
@@ -138,13 +141,55 @@ class item
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
/// \brief the internal storage for items in a category
///
/// Internal storage, strictly forward linked list with minimal space
/// requirements. Strings of size 7 or shorter are stored internally.
/// Typically, more than 99% of the strings in an mmCIF file are less
/// than 8 bytes in length.
struct
item_value
{
item_value
(
uint16_t
column_ix
,
uint16_t
length
)
:
m_next
(
nullptr
)
,
m_column_ix
(
column_ix
)
,
m_length
(
length
)
{
}
item_value
()
=
delete
;
item_value
(
const
item_value
&
)
=
delete
;
item_value
&
operator
=
(
const
item_value
&
)
=
delete
;
item_value
*
m_next
;
uint16_t
m_column_ix
;
uint16_t
m_length
;
union
{
char
m_local_data
[
8
];
char
*
m_data
;
};
static
constexpr
size_t
kBufferSize
=
sizeof
(
m_local_data
);
std
::
string_view
text
()
const
{
return
{
m_length
>=
kBufferSize
?
m_data
:
m_local_data
,
m_length
};
}
const
char
*
c_str
()
const
{
return
m_length
>=
kBufferSize
?
m_data
:
m_local_data
;
}
};
static_assert
(
sizeof
(
item_value
)
==
24
,
"sizeof(item_value) should be 24 bytes"
);
// --------------------------------------------------------------------
// Transient object to access stored data
// Transient object to access stored data
template
<
typename
RowHandle
>
struct
item_handle
struct
item_handle
{
{
using
row_handle_type
=
RowHandle
;
public
:
public
:
// conversion helper class
// conversion helper class
template
<
typename
T
,
typename
=
void
>
template
<
typename
T
,
typename
=
void
>
...
@@ -158,29 +203,6 @@ struct item_handle
...
@@ -158,29 +203,6 @@ struct item_handle
return
*
this
;
return
*
this
;
}
}
// template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
// item_handle &operator=(const T &value)
// {
// this->operator=(std::to_string(value));
// return *this;
// }
// template <typename T>
// item_handle &operator=(const std::optional<T> &value)
// {
// if (value)
// this->operator=(*value);
// else
// this->operator=("?");
// return *this;
// }
// item_handle &operator=(std::string_view value)
// {
// m_row_handle.assign(m_column, value, false);
// return *this;
// }
template
<
typename
...
Ts
>
template
<
typename
...
Ts
>
void
os
(
const
Ts
&
...
v
)
void
os
(
const
Ts
&
...
v
)
{
{
...
@@ -199,7 +221,7 @@ struct item_handle
...
@@ -199,7 +221,7 @@ struct item_handle
}
}
template
<
typename
T
>
template
<
typename
T
>
auto
value_or
(
const
T
&
dv
)
auto
value_or
(
const
T
&
dv
)
const
{
{
return
empty
()
?
dv
:
this
->
as
<
T
>
();
return
empty
()
?
dv
:
this
->
as
<
T
>
();
}
}
...
@@ -244,21 +266,12 @@ struct item_handle
...
@@ -244,21 +266,12 @@ struct item_handle
// return s_empty_result;
// return s_empty_result;
// }
// }
std
::
string_view
text
()
const
std
::
string_view
text
()
const
;
{
for
(
auto
iv
=
m_row_handle
.
m_row
->
m_head
;
iv
!=
nullptr
;
iv
=
iv
->
m_next
)
{
if
(
iv
->
m_column_ix
==
m_column
)
return
iv
->
text
();
}
return
{};
}
// bool operator!=(const std::string &s) const { return s != c_str(); }
// bool operator!=(const std::string &s) const { return s != c_str(); }
// bool operator==(const std::string &s) const { return s == c_str(); }
// bool operator==(const std::string &s) const { return s == c_str(); }
item_handle
(
uint16_t
column
,
row_handle
_type
&
row
)
item_handle
(
uint16_t
column
,
row_handle
&
row
)
:
m_column
(
column
)
:
m_column
(
column
)
,
m_row_handle
(
row
)
,
m_row_handle
(
row
)
{
{
...
@@ -266,17 +279,15 @@ struct item_handle
...
@@ -266,17 +279,15 @@ struct item_handle
private
:
private
:
uint16_t
m_column
;
uint16_t
m_column
;
row_handle_type
&
m_row_handle
;
row_handle
&
m_row_handle
;
// bool mConst = false;
static
constexpr
const
char
*
s_empty_result
=
""
;
static
constexpr
const
char
*
s_empty_result
=
""
;
};
};
// So sad that the gcc implementation of from_chars does not support floats yet...
// So sad that the gcc implementation of from_chars does not support floats yet...
template
<
typename
Row
>
template
<
typename
T
>
template
<
typename
T
>
struct
item_handle
<
Row
>
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>>>
struct
item_handle
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_arithmetic_v
<
T
>>>
{
{
using
value_type
=
std
::
remove_reference_t
<
std
::
remove_cv_t
<
T
>>
;
using
value_type
=
std
::
remove_reference_t
<
std
::
remove_cv_t
<
T
>>
;
...
@@ -348,9 +359,8 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<
...
@@ -348,9 +359,8 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<
}
}
};
};
template
<
typename
Row
>
template
<
typename
T
>
template
<
typename
T
>
struct
item_handle
<
Row
>
::
item_value_as
<
std
::
optional
<
T
>>
struct
item_handle
::
item_value_as
<
std
::
optional
<
T
>>
{
{
static
std
::
optional
<
T
>
convert
(
const
item_handle
&
ref
)
static
std
::
optional
<
T
>
convert
(
const
item_handle
&
ref
)
{
{
...
@@ -374,9 +384,8 @@ struct item_handle<Row>::item_value_as<std::optional<T>>
...
@@ -374,9 +384,8 @@ struct item_handle<Row>::item_value_as<std::optional<T>>
}
}
};
};
template
<
typename
Row
>
template
<
typename
T
>
template
<
typename
T
>
struct
item_handle
<
Row
>
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
bool
>>>
struct
item_handle
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
bool
>>>
{
{
static
bool
convert
(
const
item_handle
&
ref
)
static
bool
convert
(
const
item_handle
&
ref
)
{
{
...
@@ -394,9 +403,8 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, boo
...
@@ -394,9 +403,8 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, boo
}
}
};
};
template
<
typename
Row
>
template
<
size_t
N
>
template
<
size_t
N
>
struct
item_handle
<
Row
>
::
item_value_as
<
char
[
N
]
>
struct
item_handle
::
item_value_as
<
char
[
N
]
>
{
{
// static std::string_view convert(const item_handle &ref)
// static std::string_view convert(const item_handle &ref)
// {
// {
...
@@ -409,9 +417,8 @@ struct item_handle<Row>::item_value_as<char[N]>
...
@@ -409,9 +417,8 @@ struct item_handle<Row>::item_value_as<char[N]>
}
}
};
};
template
<
typename
Row
>
template
<
typename
T
>
template
<
typename
T
>
struct
item_handle
<
Row
>
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
const
char
*>>>
struct
item_handle
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
const
char
*>>>
{
{
// static std::string_view convert(const item_handle &ref)
// static std::string_view convert(const item_handle &ref)
// {
// {
...
@@ -424,14 +431,13 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, con
...
@@ -424,14 +431,13 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_same_v<T, con
}
}
};
};
template
<
typename
Row
>
template
<
typename
T
>
template
<
typename
T
>
struct
item_handle
<
Row
>
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
std
::
string
>>>
struct
item_handle
::
item_value_as
<
T
,
std
::
enable_if_t
<
std
::
is_same_v
<
T
,
std
::
string
>>>
{
{
static
std
::
string
convert
(
const
item_handle
&
ref
)
static
std
::
string
convert
(
const
item_handle
&
ref
)
{
{
std
::
string_view
txt
=
ref
.
text
();
std
::
string_view
txt
=
ref
.
text
();
return
{
txt
.
data
(),
txt
.
size
()
};
return
{
txt
.
data
(),
txt
.
size
()
};
}
}
static
int
compare
(
const
item_handle
&
ref
,
const
std
::
string
&
value
,
bool
icase
)
static
int
compare
(
const
item_handle
&
ref
,
const
std
::
string
&
value
,
bool
icase
)
...
...
include/cif++/v2/iterator.hpp
View file @
ab9c4d94
...
@@ -40,26 +40,24 @@ class iterator_impl
...
@@ -40,26 +40,24 @@ class iterator_impl
template
<
typename
,
typename
...
>
template
<
typename
,
typename
...
>
friend
class
iterator_impl
;
friend
class
iterator_impl
;
template
<
typename
>
friend
class
category
;
friend
class
category_t
;
static
constexpr
size_t
N
=
sizeof
...(
Ts
);
static
constexpr
size_t
N
=
sizeof
...(
Ts
);
using
category_type
=
Category
;
using
category_type
=
std
::
remove_cv_t
<
Category
>
;
using
row_type
=
std
::
conditional_t
<
std
::
is_const_v
<
category_type
>
,
const
typename
category_type
::
row
,
typename
category_type
::
row
>
;
using
row_type
=
std
::
conditional_t
<
std
::
is_const_v
<
Category
>
,
const
row
,
row
>
;
using
row_handle_type
=
std
::
conditional_t
<
std
::
is_const_v
<
category_type
>
,
const
row_handle
<
category_type
>
,
row_handle
<
category_type
>>
;
using
iterator_category
=
std
::
forward_iterator_tag
;
using
iterator_category
=
std
::
forward_iterator_tag
;
using
value_type
=
std
::
conditional_t
<
N
==
0
,
row_handle
_type
,
std
::
tuple
<
Ts
...
>>
;
using
value_type
=
std
::
conditional_t
<
N
==
0
,
row_handle
,
std
::
tuple
<
Ts
...
>>
;
using
difference_type
=
std
::
ptrdiff_t
;
using
difference_type
=
std
::
ptrdiff_t
;
using
pointer
=
std
::
conditional_t
<
N
==
0
,
row_handle
_type
,
value_type
*>
;
using
pointer
=
std
::
conditional_t
<
N
==
0
,
row_handle
,
value_type
*>
;
using
reference
=
std
::
conditional_t
<
N
==
0
,
row_handle
_type
,
value_type
&>
;
using
reference
=
std
::
conditional_t
<
N
==
0
,
row_handle
,
value_type
&>
;
iterator_impl
()
=
default
;
iterator_impl
()
=
default
;
iterator_impl
(
const
iterator_impl
&
rhs
)
=
default
;
iterator_impl
(
const
iterator_impl
&
rhs
)
=
default
;
template
<
typename
C2
,
typename
...
T2s
>
template
<
typename
C2
,
typename
...
T2s
>
iterator_impl
(
const
iterator_impl
<
C2
,
T2s
...
>
&
rhs
)
iterator_impl
(
const
iterator_impl
<
C2
,
T2s
...
>
&
rhs
)
:
m_category
(
rhs
.
m_category
)
:
m_category
(
rhs
.
m_category
)
,
m_current
(
rhs
.
m_current
)
,
m_current
(
rhs
.
m_current
)
...
@@ -68,10 +66,10 @@ class iterator_impl
...
@@ -68,10 +66,10 @@ class iterator_impl
{
{
}
}
iterator_impl
(
category_type
&
cat
,
row_type
*
current
)
iterator_impl
(
Category
&
cat
,
row
*
current
)
:
m_category
(
&
cat
)
:
m_category
(
const_cast
<
category_type
*>
(
&
cat
)
)
,
m_current
(
current
)
,
m_current
(
current
)
,
m_value
(
cat
,
*
current
)
,
m_value
(
*
m_category
,
*
current
)
{
{
static_assert
(
N
==
0
,
"Only valid if this is a row iterator, not a row<xxx> iterator"
);
static_assert
(
N
==
0
,
"Only valid if this is a row iterator, not a row<xxx> iterator"
);
}
}
...
@@ -139,10 +137,15 @@ class iterator_impl
...
@@ -139,10 +137,15 @@ class iterator_impl
return
&
m_value
;
return
&
m_value
;
}
}
row_type
row
()
const
// const row_type *get_row() const
{
// {
return
m_current
;
// return m_current;
}
// }
// row_type *get_row()
// {
// return m_current;
// }
iterator_impl
&
operator
++
()
iterator_impl
&
operator
++
()
{
{
...
@@ -183,7 +186,7 @@ class iterator_impl
...
@@ -183,7 +186,7 @@ class iterator_impl
{
{
if
(
m_current
!=
nullptr
)
if
(
m_current
!=
nullptr
)
{
{
row_handle
_type
rh
{
*
m_category
,
*
m_current
};
row_handle
rh
{
*
m_category
,
*
m_current
};
return
std
::
tuple
<
Ts
...
>
{
rh
[
m_column_ix
[
Is
]].
template
as
<
Ts
>
()...};
return
std
::
tuple
<
Ts
...
>
{
rh
[
m_column_ix
[
Is
]].
template
as
<
Ts
>
()...};
}
}
...
@@ -206,8 +209,7 @@ class iterator_proxy
...
@@ -206,8 +209,7 @@ class iterator_proxy
static
constexpr
const
size_t
N
=
sizeof
...(
Ts
);
static
constexpr
const
size_t
N
=
sizeof
...(
Ts
);
using
category_type
=
Category
;
using
category_type
=
Category
;
using
row_type
=
std
::
conditional_t
<
std
::
is_const_v
<
category_type
>
,
const
typename
category_type
::
row
,
typename
category_type
::
row
>
;
using
row_type
=
std
::
conditional_t
<
std
::
is_const_v
<
category_type
>
,
const
row
,
row
>
;
using
row_handle_type
=
std
::
conditional_t
<
std
::
is_const_v
<
category_type
>
,
const
row_handle
<
category_type
>
,
row_handle
<
category_type
>>
;
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
>
;
...
@@ -230,8 +232,8 @@ class iterator_proxy
...
@@ -230,8 +232,8 @@ class iterator_proxy
size_t
size
()
const
{
return
std
::
distance
(
begin
(),
end
());
}
size_t
size
()
const
{
return
std
::
distance
(
begin
(),
end
());
}
row_type
front
()
{
return
*
begin
();
}
// row
front() { return *begin(); }
row_type
back
()
{
return
*
(
std
::
prev
(
end
()));
}
// row
back() { return *(std::prev(end())); }
category_type
&
category
()
const
{
return
*
m_category
;
}
category_type
&
category
()
const
{
return
*
m_category
;
}
...
@@ -249,114 +251,116 @@ class iterator_proxy
...
@@ -249,114 +251,116 @@ class iterator_proxy
std
::
array
<
size_t
,
N
>
m_column_ix
;
std
::
array
<
size_t
,
N
>
m_column_ix
;
};
};
//
//
--------------------------------------------------------------------
// --------------------------------------------------------------------
//
//
conditional iterator proxy
// conditional iterator proxy
//
template <typename CategoryType, typename... Ts>
template
<
typename
CategoryType
,
typename
...
Ts
>
//
class conditional_iterator_proxy
class
conditional_iterator_proxy
//
{
{
//
public:
public
:
//
static constexpr const size_t N = sizeof...(Ts);
static
constexpr
const
size_t
N
=
sizeof
...(
Ts
);
// using base_iterator = iterator_impl<CategoryType, Ts...>;
using
category_type
=
std
::
remove_cv_t
<
CategoryType
>
;
// using value_type = typename base_iterator::value_type;
// using row_type = typename base_iterator::row_type;
// using row_iterator = iterator_impl<row_type>;
// class conditional_iterator_impl
using
base_iterator
=
iterator_impl
<
CategoryType
,
Ts
...
>
;
// {
using
value_type
=
typename
base_iterator
::
value_type
;
// public:
using
row_type
=
typename
base_iterator
::
row_type
;
// using iterator_category = std::forward_iterator_tag;
using
row_iterator
=
iterator_impl
<
CategoryType
>
;
// using value_type = conditional_iterator_proxy::value_type;
// using difference_type = std::ptrdiff_t;
// using pointer = value_type *;
// using reference = value_type &;
// conditional_iterator_impl(CategoryType &cat, row_iterator pos, const Condition &cond, const std::array<size_t, N> &cix);
class
conditional_iterator_impl
// conditional_iterator_impl(const conditional_iterator_impl &i) = default;
{
// conditional_iterator_impl &operator=(const conditional_iterator_impl &i) = default;
public
:
using
iterator_category
=
std
::
forward_iterator_tag
;
using
value_type
=
conditional_iterator_proxy
::
value_type
;
using
difference_type
=
std
::
ptrdiff_t
;
using
pointer
=
value_type
*
;
using
reference
=
row_handle
;
conditional_iterator_impl
(
CategoryType
&
cat
,
row_iterator
pos
,
const
condition
&
cond
,
const
std
::
array
<
size_t
,
N
>
&
cix
);
conditional_iterator_impl
(
const
conditional_iterator_impl
&
i
)
=
default
;
conditional_iterator_impl
&
operator
=
(
const
conditional_iterator_impl
&
i
)
=
default
;
//
virtual ~conditional_iterator_impl() = default;
virtual
~
conditional_iterator_impl
()
=
default
;
//
reference operator*()
reference
operator
*
()
//
{
{
//
return *mBegin;
return
*
mBegin
;
//
}
}
//
pointer operator->()
pointer
operator
->
()
//
{
{
//
return &*mBegin;
return
&*
mBegin
;
//
}
}
//
conditional_iterator_impl &operator++()
conditional_iterator_impl
&
operator
++
()
//
{
{
//
while (mBegin != mEnd)
while
(
mBegin
!=
mEnd
)
//
{
{
//
if (++mBegin == mEnd)
if
(
++
mBegin
==
mEnd
)
//
break;
break
;
// if ((*mCondition)(*mCat, mBegin.row()
))
if
((
*
m_condition
)(
*
mBegin
))
//
break;
break
;
//
}
}
//
return *this;
return
*
this
;
//
}
}
//
conditional_iterator_impl operator++(int)
conditional_iterator_impl
operator
++
(
int
)
//
{
{
//
conditional_iterator_impl result(*this);
conditional_iterator_impl
result
(
*
this
);
//
this->operator++();
this
->
operator
++
();
//
return result;
return
result
;
//
}
}
//
bool operator==(const conditional_iterator_impl &rhs) const { return mBegin == rhs.mBegin; }
bool
operator
==
(
const
conditional_iterator_impl
&
rhs
)
const
{
return
mBegin
==
rhs
.
mBegin
;
}
//
bool operator!=(const conditional_iterator_impl &rhs) const { return mBegin != rhs.mBegin; }
bool
operator
!=
(
const
conditional_iterator_impl
&
rhs
)
const
{
return
mBegin
!=
rhs
.
mBegin
;
}
//
template <typename IRowType, typename... ITs>
template
<
typename
IRowType
,
typename
...
ITs
>
//
bool operator==(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin == rhs; }
bool
operator
==
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
return
mBegin
==
rhs
;
}
//
template <typename IRowType, typename... ITs>
template
<
typename
IRowType
,
typename
...
ITs
>
//
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin != rhs; }
bool
operator
!=
(
const
iterator_impl
<
IRowType
,
ITs
...
>
&
rhs
)
const
{
return
mBegin
!=
rhs
;
}
//
private:
private
:
//
CategoryType *mCat;
CategoryType
*
mCat
;
//
base_iterator mBegin, mEnd;
base_iterator
mBegin
,
mEnd
;
// const Condition *mC
ondition;
const
condition
*
m_c
ondition
;
//
};
};
//
using iterator = conditional_iterator_impl;
using
iterator
=
conditional_iterator_impl
;
//
using reference = typename iterator::reference;
using
reference
=
typename
iterator
::
reference
;
//
template <typename... Ns>
template
<
typename
...
Ns
>
// conditional_iterator_proxy(CategoryType &cat, row_iterator pos, C
ondition &&cond, Ns... names);
conditional_iterator_proxy
(
CategoryType
&
cat
,
row_iterator
pos
,
c
ondition
&&
cond
,
Ns
...
names
);
//
conditional_iterator_proxy(conditional_iterator_proxy &&p);
conditional_iterator_proxy
(
conditional_iterator_proxy
&&
p
);
//
conditional_iterator_proxy &operator=(conditional_iterator_proxy &&p);
conditional_iterator_proxy
&
operator
=
(
conditional_iterator_proxy
&&
p
);
//
conditional_iterator_proxy(const conditional_iterator_proxy &) = delete;
conditional_iterator_proxy
(
const
conditional_iterator_proxy
&
)
=
delete
;
//
conditional_iterator_proxy &operator=(const conditional_iterator_proxy &) = delete;
conditional_iterator_proxy
&
operator
=
(
const
conditional_iterator_proxy
&
)
=
delete
;
//
iterator begin() const;
iterator
begin
()
const
;
//
iterator end() const;
iterator
end
()
const
;
//
bool empty() const;
bool
empty
()
const
;
//
explicit operator bool() const { return not empty(); }
explicit
operator
bool
()
const
{
return
not
empty
();
}
//
size_t size() const { return std::distance(begin(), end()); }
size_t
size
()
const
{
return
std
::
distance
(
begin
(),
end
());
}
// row_type
front() { return *begin(); }
// row
front() { return *begin(); }
//
CategoryType &category() const { return *mCat; }
CategoryType
&
category
()
const
{
return
*
mCat
;
}
//
void swap(conditional_iterator_proxy &rhs);
void
swap
(
conditional_iterator_proxy
&
rhs
);
//
private:
private
:
//
CategoryType *mCat;
CategoryType
*
mCat
;
// Condition mC
ondition;
condition
m_c
ondition
;
//
row_iterator mCBegin, mCEnd;
row_iterator
mCBegin
,
mCEnd
;
//
std::array<size_t, N> mCix;
std
::
array
<
size_t
,
N
>
mCix
;
//
};
};
// --------------------------------------------------------------------
// --------------------------------------------------------------------
...
@@ -385,80 +389,80 @@ iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos,
...
@@ -385,80 +389,80 @@ iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos,
// --------------------------------------------------------------------
// --------------------------------------------------------------------
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
conditional_iterator_proxy
<
Category
,
Ts
...
>::
conditional_iterator_impl
::
conditional_iterator_impl
(
// Category &cat, row_iterator pos, const C
ondition &cond, const std::array<size_t, N> &cix)
Category
&
cat
,
row_iterator
pos
,
const
c
ondition
&
cond
,
const
std
::
array
<
size_t
,
N
>
&
cix
)
//
: mCat(&cat)
:
mCat
(
&
cat
)
//
, mBegin(pos, cix)
,
mBegin
(
pos
,
cix
)
//
, mEnd(cat.end(), cix)
,
mEnd
(
cat
.
end
(),
cix
)
// , mC
ondition(&cond)
,
m_c
ondition
(
&
cond
)
//
{
{
//
}
}
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(conditional_iterator_proxy &&p)
conditional_iterator_proxy
<
Category
,
Ts
...
>::
conditional_iterator_proxy
(
conditional_iterator_proxy
&&
p
)
//
: mCat(nullptr)
:
mCat
(
nullptr
)
//
, mCBegin(p.mCBegin)
,
mCBegin
(
p
.
mCBegin
)
//
, mCEnd(p.mCEnd)
,
mCEnd
(
p
.
mCEnd
)
//
, mCix(p.mCix)
,
mCix
(
p
.
mCix
)
//
{
{
//
std::swap(mCat, p.mCat);
std
::
swap
(
mCat
,
p
.
mCat
);
//
std::swap(mCix, p.mCix);
std
::
swap
(
mCix
,
p
.
mCix
);
// mCondition.swap(p.mC
ondition);
m_condition
.
swap
(
p
.
m_c
ondition
);
//
}
}
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
template <typename... Ns>
template
<
typename
...
Ns
>
// conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category &cat, row_iterator pos, C
ondition &&cond, Ns... names)
conditional_iterator_proxy
<
Category
,
Ts
...
>::
conditional_iterator_proxy
(
Category
&
cat
,
row_iterator
pos
,
c
ondition
&&
cond
,
Ns
...
names
)
//
: mCat(&cat)
:
mCat
(
&
cat
)
// , mC
ondition(std::move(cond))
,
m_c
ondition
(
std
::
move
(
cond
))
//
, 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 column names should be equal to number of requested value types"
);
// mC
ondition.prepare(cat);
m_c
ondition
.
prepare
(
cat
);
// while (mCBegin != mCEnd and not mCondition(*mCat, mCBegin.row()
))
while
(
mCBegin
!=
mCEnd
and
not
m_condition
(
*
mCBegin
))
//
++mCBegin;
++
mCBegin
;
//
size_t i = 0;
size_t
i
=
0
;
//
((mCix[i++] = mCat->getColumnIndex(names)), ...);
((
mCix
[
i
++
]
=
mCat
->
getColumnIndex
(
names
)),
...);
//
}
}
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
conditional_iterator_proxy<Category, Ts...> &conditional_iterator_proxy<Category, Ts...>::operator=(conditional_iterator_proxy &&p)
conditional_iterator_proxy
<
Category
,
Ts
...
>
&
conditional_iterator_proxy
<
Category
,
Ts
...
>::
operator
=
(
conditional_iterator_proxy
&&
p
)
//
{
{
//
swap(p);
swap
(
p
);
//
return *this;
return
*
this
;
//
}
}
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::begin() const
typename
conditional_iterator_proxy
<
Category
,
Ts
...
>::
iterator
conditional_iterator_proxy
<
Category
,
Ts
...
>::
begin
()
const
//
{
{
// return iterator(*mCat, mCBegin, mC
ondition, mCix);
return
iterator
(
*
mCat
,
mCBegin
,
m_c
ondition
,
mCix
);
//
}
}
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::end() const
typename
conditional_iterator_proxy
<
Category
,
Ts
...
>::
iterator
conditional_iterator_proxy
<
Category
,
Ts
...
>::
end
()
const
//
{
{
// return iterator(*mCat, mCEnd, mC
ondition, mCix);
return
iterator
(
*
mCat
,
mCEnd
,
m_c
ondition
,
mCix
);
//
}
}
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
bool conditional_iterator_proxy<Category, Ts...>::empty() const
bool
conditional_iterator_proxy
<
Category
,
Ts
...
>::
empty
()
const
//
{
{
//
return mCBegin == mCEnd;
return
mCBegin
==
mCEnd
;
//
}
}
//
template <typename Category, typename... Ts>
template
<
typename
Category
,
typename
...
Ts
>
//
void conditional_iterator_proxy<Category, Ts...>::swap(conditional_iterator_proxy &rhs)
void
conditional_iterator_proxy
<
Category
,
Ts
...
>::
swap
(
conditional_iterator_proxy
&
rhs
)
//
{
{
//
std::swap(mCat, rhs.mCat);
std
::
swap
(
mCat
,
rhs
.
mCat
);
// mCondition.swap(rhs.mC
ondition);
m_condition
.
swap
(
rhs
.
m_c
ondition
);
//
std::swap(mCBegin, rhs.mCBegin);
std
::
swap
(
mCBegin
,
rhs
.
mCBegin
);
//
std::swap(mCEnd, rhs.mCEnd);
std
::
swap
(
mCEnd
,
rhs
.
mCEnd
);
//
std::swap(mCix, rhs.mCix);
std
::
swap
(
mCix
,
rhs
.
mCix
);
//
}
}
}
//
namespace
cif
::
v2
}
//
namespace
cif
::
v2
\ No newline at end of file
include/cif++/v2/parser.hpp
View file @
ab9c4d94
...
@@ -26,19 +26,7 @@
...
@@ -26,19 +26,7 @@
#pragma once
#pragma once
#include <cassert>
#include <cif++/v2/row.hpp>
#include <iostream>
#include <map>
#include <stack>
#include <regex>
#include <cif++/v2/forward_decl.hpp>
#include <cif++/CifUtils.hpp>
namespace
cif
{
extern
int
VERBOSE
;
}
namespace
cif
::
v2
namespace
cif
::
v2
{
{
...
@@ -61,16 +49,7 @@ class sac_parser
...
@@ -61,16 +49,7 @@ class sac_parser
public
:
public
:
using
datablock_index
=
std
::
map
<
std
::
string
,
std
::
size_t
>
;
using
datablock_index
=
std
::
map
<
std
::
string
,
std
::
size_t
>
;
sac_parser
(
std
::
istream
&
is
,
bool
init
=
true
)
sac_parser
(
std
::
istream
&
is
,
bool
init
=
true
);
:
m_source
(
is
)
{
m_validate
=
true
;
m_line_nr
=
1
;
m_bol
=
true
;
if
(
init
)
m_lookahead
=
get_next_token
();
}
virtual
~
sac_parser
()
=
default
;
virtual
~
sac_parser
()
=
default
;
...
@@ -201,719 +180,31 @@ class sac_parser
...
@@ -201,719 +180,31 @@ class sac_parser
// get_next_char takes a char from the buffer, or if it is empty
// get_next_char takes a char from the buffer, or if it is empty
// from the istream. This function also does carriage/linefeed
// from the istream. This function also does carriage/linefeed
// translation.
// translation.
int
get_next_char
()
int
get_next_char
();
{
int
result
;
if
(
m_buffer
.
empty
())
result
=
m_source
.
get
();
else
{
result
=
m_buffer
.
top
();
m_buffer
.
pop
();
}
// very simple CR/LF translation into LF
if
(
result
==
'\r'
)
{
int
lookahead
=
m_source
.
get
();
if
(
lookahead
!=
'\n'
)
m_buffer
.
push
(
lookahead
);
result
=
'\n'
;
}
m_token_value
+=
static_cast
<
char
>
(
result
);
if
(
result
==
'\n'
)
void
retract
();
++
m_line_nr
;
if
(
VERBOSE
>=
6
)
{
std
::
cerr
<<
"get_next_char => "
;
if
(
iscntrl
(
result
)
or
not
isprint
(
result
))
std
::
cerr
<<
int
(
result
)
<<
std
::
endl
;
else
std
::
cerr
<<
char
(
result
)
<<
std
::
endl
;
}
return
result
;
}
void
retract
()
{
assert
(
not
m_token_value
.
empty
());
char
ch
=
m_token_value
.
back
();
int
restart
(
int
start
);
if
(
ch
==
'\n'
)
--
m_line_nr
;
m_buffer
.
push
(
ch
);
m_token_value
.
pop_back
();
}
int
restart
(
int
start
)
{
int
result
=
0
;
while
(
not
m_token_value
.
empty
())
retract
();
switch
(
start
)
{
case
State
:
:
Start
:
result
=
State
::
Float
;
break
;
case
State
:
:
Float
:
result
=
State
::
Int
;
break
;
case
State
:
:
Int
:
result
=
State
::
Value
;
break
;
default:
error
(
"Invalid state in SacParser"
);
}
m_bol
=
false
;
return
result
;
}
CIFToken
get_next_token
()
{
const
auto
kEOF
=
std
::
char_traits
<
char
>::
eof
();
CIFToken
result
=
CIFToken
::
Unknown
;
int
quoteChar
=
0
;
int
state
=
State
::
Start
,
start
=
State
::
Start
;
m_bol
=
false
;
m_token_value
.
clear
();
mTokenType
=
CIFValue
::
Unknown
;
while
(
result
==
CIFToken
::
Unknown
)
{
auto
ch
=
get_next_char
();
switch
(
state
)
CIFToken
get_next_token
();
{
case
State
:
:
Start
:
if
(
ch
==
kEOF
)
result
=
CIFToken
::
Eof
;
else
if
(
ch
==
'\n'
)
{
m_bol
=
true
;
state
=
State
::
White
;
}
else
if
(
ch
==
' '
or
ch
==
'\t'
)
state
=
State
::
White
;
else
if
(
ch
==
'#'
)
state
=
State
::
Comment
;
else
if
(
ch
==
'_'
)
state
=
State
::
Tag
;
else
if
(
ch
==
';'
and
m_bol
)
state
=
State
::
TextField
;
else
if
(
ch
==
'\''
or
ch
==
'"'
)
{
quoteChar
=
ch
;
state
=
State
::
QuotedString
;
}
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
White
:
void
match
(
CIFToken
token
);
if
(
ch
==
kEOF
)
result
=
CIFToken
::
Eof
;
else
if
(
not
isspace
(
ch
))
{
state
=
State
::
Start
;
retract
();
m_token_value
.
clear
();
}
else
m_bol
=
(
ch
==
'\n'
);
break
;
case
State
:
:
Comment
:
if
(
ch
==
'\n'
)
{
state
=
State
::
Start
;
m_bol
=
true
;
m_token_value
.
clear
();
}
else
if
(
ch
==
kEOF
)
result
=
CIFToken
::
Eof
;
else
if
(
not
is_any_print
(
ch
))
error
(
"invalid character in comment"
);
break
;
case
State
:
:
TextField
:
if
(
ch
==
'\n'
)
state
=
State
::
TextField
+
1
;
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
else
if
(
not
is_any_print
(
ch
))
warning
(
"invalid character in text field '"
+
std
::
string
({
static_cast
<
char
>
(
ch
)})
+
"' ("
+
std
::
to_string
((
int
)
ch
)
+
")"
);
break
;
case
State
:
:
TextField
+
1
:
if
(
is_text_lead
(
ch
)
or
ch
==
' '
or
ch
==
'\t'
)
state
=
State
::
TextField
;
else
if
(
ch
==
';'
)
{
assert
(
m_token_value
.
length
()
>=
2
);
m_token_value
=
m_token_value
.
substr
(
1
,
m_token_value
.
length
()
-
3
);
mTokenType
=
CIFValue
::
TextField
;
result
=
CIFToken
::
Value
;
}
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
else
if
(
ch
!=
'\n'
)
error
(
"invalid character in text field"
);
break
;
case
State
:
:
QuotedString
:
if
(
ch
==
kEOF
)
error
(
"unterminated quoted string"
);
else
if
(
ch
==
quoteChar
)
state
=
State
::
QuotedStringQuote
;
else
if
(
not
is_any_print
(
ch
))
warning
(
"invalid character in quoted string: '"
+
std
::
string
({
static_cast
<
char
>
(
ch
)})
+
'\''
);
break
;
case
State
:
:
QuotedStringQuote
:
if
(
is_white
(
ch
))
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
String
;
if
(
m_token_value
.
length
()
<
2
)
error
(
"Invalid quoted string token"
);
m_token_value
=
m_token_value
.
substr
(
1
,
m_token_value
.
length
()
-
2
);
}
else
if
(
ch
==
quoteChar
)
;
else
if
(
is_any_print
(
ch
))
state
=
State
::
QuotedString
;
else
if
(
ch
==
kEOF
)
error
(
"unterminated quoted string"
);
else
error
(
"invalid character in quoted string"
);
break
;
case
State
:
:
Tag
:
if
(
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
Tag
;
}
break
;
case
State
:
:
Float
:
if
(
ch
==
'+'
or
ch
==
'-'
)
{
state
=
State
::
Float
+
1
;
}
else
if
(
isdigit
(
ch
))
state
=
State
::
Float
+
1
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Float
+
1
:
// if (ch == '(') // numeric???
// mState = State::NumericSuffix;
// else
if
(
ch
==
'.'
)
state
=
State
::
Float
+
2
;
else
if
(
tolower
(
ch
)
==
'e'
)
state
=
State
::
Float
+
3
;
else
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Int
;
}
else
state
=
start
=
restart
(
start
);
break
;
// parsed '.'
case
State
:
:
Float
+
2
:
if
(
tolower
(
ch
)
==
'e'
)
state
=
State
::
Float
+
3
;
else
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Float
;
}
else
state
=
start
=
restart
(
start
);
break
;
// parsed 'e'
case
State
:
:
Float
+
3
:
if
(
ch
==
'-'
or
ch
==
'+'
)
state
=
State
::
Float
+
4
;
else
if
(
isdigit
(
ch
))
state
=
State
::
Float
+
5
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Float
+
4
:
if
(
isdigit
(
ch
))
state
=
State
::
Float
+
5
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Float
+
5
:
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Float
;
}
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Int
:
if
(
isdigit
(
ch
)
or
ch
==
'+'
or
ch
==
'-'
)
state
=
State
::
Int
+
1
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Int
+
1
:
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Int
;
}
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Value
:
if
(
ch
==
'_'
)
{
std
::
string
s
=
toLowerCopy
(
m_token_value
);
if
(
s
==
"global_"
)
result
=
CIFToken
::
GLOBAL
;
else
if
(
s
==
"stop_"
)
result
=
CIFToken
::
STOP
;
else
if
(
s
==
"loop_"
)
result
=
CIFToken
::
LOOP
;
else
if
(
s
==
"data_"
)
{
state
=
State
::
DATA
;
continue
;
}
else
if
(
s
==
"save_"
)
{
state
=
State
::
SAVE
;
continue
;
}
}
if
(
result
==
CIFToken
::
Unknown
and
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
Value
;
if
(
m_token_value
==
"."
)
mTokenType
=
CIFValue
::
Inapplicable
;
else
if
(
m_token_value
==
"?"
)
{
mTokenType
=
CIFValue
::
Unknown
;
m_token_value
.
clear
();
}
}
break
;
case
State
:
:
DATA
:
case
State
:
:
SAVE
:
if
(
not
is_non_blank
(
ch
))
{
retract
();
if
(
state
==
State
::
DATA
)
result
=
CIFToken
::
DATA
;
else
result
=
CIFToken
::
SAVE
;
m_token_value
.
erase
(
m_token_value
.
begin
(),
m_token_value
.
begin
()
+
5
);
}
break
;
default:
assert
(
false
);
error
(
"Invalid state in get_next_token"
);
break
;
}
}
if
(
VERBOSE
>=
5
)
{
std
::
cerr
<<
get_token_name
(
result
);
if
(
mTokenType
!=
CIFValue
::
Unknown
)
std
::
cerr
<<
' '
<<
get_value_name
(
mTokenType
);
if
(
result
!=
CIFToken
::
Eof
)
std
::
cerr
<<
" "
<<
std
::
quoted
(
m_token_value
);
std
::
cerr
<<
std
::
endl
;
}
return
result
;
}
void
match
(
CIFToken
token
)
{
if
(
m_lookahead
!=
token
)
error
(
std
::
string
(
"Unexpected token, expected "
)
+
get_token_name
(
token
)
+
" but found "
+
get_token_name
(
m_lookahead
));
m_lookahead
=
get_next_token
();
}
public
:
public
:
bool
parse_single_datablock
(
const
std
::
string
&
datablock
)
bool
parse_single_datablock
(
const
std
::
string
&
datablock
);
{
// first locate the start, as fast as we can
auto
&
sb
=
*
m_source
.
rdbuf
();
enum
{
start
,
comment
,
string
,
string_quote
,
qstring
,
data
}
state
=
start
;
int
quote
=
0
;
bool
bol
=
true
;
std
::
string
dblk
=
"data_"
+
datablock
;
std
::
string
::
size_type
si
=
0
;
bool
found
=
false
;
for
(
auto
ch
=
sb
.
sbumpc
();
not
found
and
ch
!=
std
::
streambuf
::
traits_type
::
eof
();
ch
=
sb
.
sbumpc
())
{
switch
(
state
)
{
case
start
:
switch
(
ch
)
{
case
'#'
:
state
=
comment
;
break
;
case
'd'
:
case
'D'
:
state
=
data
;
si
=
1
;
break
;
case
'\''
:
case
'"'
:
state
=
string
;
quote
=
ch
;
break
;
case
';'
:
if
(
bol
)
state
=
qstring
;
break
;
}
break
;
case
comment
:
if
(
ch
==
'\n'
)
state
=
start
;
break
;
case
string
:
datablock_index
index_datablocks
();
if
(
ch
==
quote
)
state
=
string_quote
;
break
;
case
string_quote
:
bool
parse_single_datablock
(
const
std
::
string
&
datablock
,
const
datablock_index
&
index
);
if
(
std
::
isspace
(
ch
))
state
=
start
;
else
state
=
string
;
break
;
case
qstring
:
void
parse_file
();
if
(
ch
==
';'
and
bol
)
state
=
start
;
break
;
case
data
:
if
(
isspace
(
ch
)
and
dblk
[
si
]
==
0
)
found
=
true
;
else
if
(
dblk
[
si
++
]
!=
ch
)
state
=
start
;
break
;
}
bol
=
(
ch
==
'\n'
);
}
if
(
found
)
{
produce_datablock
(
datablock
);
m_lookahead
=
get_next_token
();
parse_datablock
();
}
return
found
;
}
datablock_index
index_datablocks
()
{
datablock_index
index
;
// first locate the start, as fast as we can
auto
&
sb
=
*
m_source
.
rdbuf
();
enum
{
start
,
comment
,
string
,
string_quote
,
qstring
,
data
,
data_name
}
state
=
start
;
int
quote
=
0
;
bool
bol
=
true
;
const
char
dblk
[]
=
"data_"
;
std
::
string
::
size_type
si
=
0
;
std
::
string
datablock
;
for
(
auto
ch
=
sb
.
sbumpc
();
ch
!=
std
::
streambuf
::
traits_type
::
eof
();
ch
=
sb
.
sbumpc
())
{
switch
(
state
)
{
case
start
:
switch
(
ch
)
{
case
'#'
:
state
=
comment
;
break
;
case
'd'
:
case
'D'
:
state
=
data
;
si
=
1
;
break
;
case
'\''
:
case
'"'
:
state
=
string
;
quote
=
ch
;
break
;
case
';'
:
if
(
bol
)
state
=
qstring
;
break
;
}
break
;
case
comment
:
if
(
ch
==
'\n'
)
state
=
start
;
break
;
case
string
:
if
(
ch
==
quote
)
state
=
string_quote
;
break
;
case
string_quote
:
if
(
std
::
isspace
(
ch
))
state
=
start
;
else
state
=
string
;
break
;
case
qstring
:
if
(
ch
==
';'
and
bol
)
state
=
start
;
break
;
case
data
:
if
(
dblk
[
si
]
==
0
and
is_non_blank
(
ch
))
{
datablock
=
{
static_cast
<
char
>
(
ch
)};
state
=
data_name
;
}
else
if
(
dblk
[
si
++
]
!=
ch
)
state
=
start
;
break
;
case
data_name
:
if
(
is_non_blank
(
ch
))
datablock
.
insert
(
datablock
.
end
(),
char
(
ch
));
else
if
(
isspace
(
ch
))
{
if
(
not
datablock
.
empty
())
index
[
datablock
]
=
m_source
.
tellg
();
state
=
start
;
}
else
state
=
start
;
break
;
}
bol
=
(
ch
==
'\n'
);
}
return
index
;
}
bool
parse_single_datablock
(
const
std
::
string
&
datablock
,
const
datablock_index
&
index
)
{
bool
result
=
false
;
auto
i
=
index
.
find
(
datablock
);
if
(
i
!=
index
.
end
())
{
m_source
.
seekg
(
i
->
second
);
produce_datablock
(
datablock
);
m_lookahead
=
get_next_token
();
parse_datablock
();
result
=
true
;
}
return
result
;
}
void
parse_file
()
{
while
(
m_lookahead
!=
CIFToken
::
Eof
)
{
switch
(
m_lookahead
)
{
case
CIFToken
:
:
GLOBAL
:
parse_global
();
break
;
case
CIFToken
:
:
DATA
:
produce_datablock
(
m_token_value
);
match
(
CIFToken
::
DATA
);
parse_datablock
();
break
;
default
:
error
(
"This file does not seem to be an mmCIF file"
);
break
;
}
}
}
protected
:
protected
:
void
parse_global
()
void
parse_global
();
{
match
(
CIFToken
::
GLOBAL
);
while
(
m_lookahead
==
CIFToken
::
Tag
)
{
match
(
CIFToken
::
Tag
);
match
(
CIFToken
::
Value
);
}
}
void
parse_datablock
()
{
std
::
string
cat
;
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
Tag
or
m_lookahead
==
CIFToken
::
SAVE
)
{
switch
(
m_lookahead
)
{
case
CIFToken
:
:
LOOP
:
{
cat
.
clear
();
// should start a new category
match
(
CIFToken
::
LOOP
);
std
::
vector
<
std
::
string
>
tags
;
while
(
m_lookahead
==
CIFToken
::
Tag
)
{
std
::
string
catName
,
itemName
;
std
::
tie
(
catName
,
itemName
)
=
splitTagName
(
m_token_value
);
if
(
cat
.
empty
())
{
produce_category
(
catName
);
cat
=
catName
;
}
else
if
(
not
iequals
(
cat
,
catName
))
error
(
"inconsistent categories in loop_"
);
tags
.
push_back
(
itemName
);
match
(
CIFToken
::
Tag
);
}
while
(
m_lookahead
==
CIFToken
::
Value
)
{
produce_row
();
for
(
auto
tag
:
tags
)
{
produce_item
(
cat
,
tag
,
m_token_value
);
match
(
CIFToken
::
Value
);
}
}
cat
.
clear
();
break
;
}
case
CIFToken
:
:
Tag
:
{
std
::
string
catName
,
itemName
;
std
::
tie
(
catName
,
itemName
)
=
splitTagName
(
m_token_value
);
if
(
not
iequals
(
cat
,
catName
))
{
produce_category
(
catName
);
cat
=
catName
;
produce_row
();
}
match
(
CIFToken
::
Tag
);
void
parse_datablock
(
);
produce_item
(
cat
,
itemName
,
m_token_value
);
virtual
void
parse_save_frame
();
match
(
CIFToken
::
Value
);
break
;
}
case
CIFToken
:
:
SAVE
:
parse_save_frame
();
break
;
default
:
assert
(
false
);
break
;
}
}
}
virtual
void
parse_save_frame
()
{
error
(
"A regular CIF file should not contain a save frame"
);
}
void
error
(
const
std
::
string
&
msg
)
void
error
(
const
std
::
string
&
msg
)
{
{
...
@@ -966,61 +257,28 @@ class sac_parser
...
@@ -966,61 +257,28 @@ class sac_parser
// --------------------------------------------------------------------
// --------------------------------------------------------------------
template
<
typename
Alloc
,
typename
File
,
typename
Datablock
,
typename
Category
>
class
parser
:
public
sac_parser
class
parser_t
:
public
sac_parser
{
{
public
:
public
:
using
file_type
=
File
;
parser
(
std
::
istream
&
is
,
file
&
file
)
using
datablock_type
=
Datablock
;
using
category_type
=
Category
;
using
row_handle_type
=
category_type
::
reference
;
parser_t
(
std
::
istream
&
is
,
file_type
&
file
)
:
sac_parser
(
is
)
:
sac_parser
(
is
)
,
m_file
(
file
)
,
m_file
(
file
)
{
{
}
}
void
produce_datablock
(
const
std
::
string
&
name
)
override
void
produce_datablock
(
const
std
::
string
&
name
)
override
;
{
const
auto
&
[
iter
,
ignore
]
=
m_file
.
emplace
(
name
);
m_datablock
=
&
(
*
iter
);
}
void
produce_category
(
const
std
::
string
&
name
)
override
void
produce_category
(
const
std
::
string
&
name
)
override
;
{
if
(
VERBOSE
>=
4
)
std
::
cerr
<<
"producing category "
<<
name
<<
std
::
endl
;
std
::
tie
(
m_category
,
std
::
ignore
)
=
m_datablock
->
emplace
(
name
);
}
void
produce_row
()
override
{
if
(
VERBOSE
>=
4
)
std
::
cerr
<<
"producing row for category "
<<
m_category
->
name
()
<<
std
::
endl
;
m_category
->
emplace
({});
void
produce_row
()
override
;
m_row
=
m_category
->
back
();
// m_row.lineNr(m_line_nr);
}
void
produce_item
(
const
std
::
string
&
category
,
const
std
::
string
&
item
,
const
std
::
string
&
value
)
override
{
if
(
VERBOSE
>=
4
)
std
::
cerr
<<
"producing _"
<<
category
<<
'.'
<<
item
<<
" -> "
<<
value
<<
std
::
endl
;
if
(
not
iequals
(
category
,
m_category
->
name
()))
void
produce_item
(
const
std
::
string
&
category
,
const
std
::
string
&
item
,
const
std
::
string
&
value
)
override
;
error
(
"inconsistent categories in loop_"
);
m_row
[
item
]
=
m_token_value
;
}
protected
:
protected
:
file
_type
&
m_file
;
file
&
m_file
;
datablock
_type
*
m_datablock
;
datablock
*
m_datablock
=
nullptr
;
datablock_type
::
iterator
m_category
;
category
*
m_category
=
nullptr
;
row_handle
_type
m_row
;
row_handle
m_row
;
};
};
}
// namespace cif::v2
}
// namespace cif::v2
include/cif++/v2/row.hpp
View file @
ab9c4d94
...
@@ -27,37 +27,26 @@
...
@@ -27,37 +27,26 @@
#pragma once
#pragma once
#include <cif++/v2/item.hpp>
#include <cif++/v2/item.hpp>
#include <cif++/v2/condition.hpp>
namespace
cif
::
v2
namespace
cif
::
v2
{
{
template
<
typename
>
class
row_handle
;
namespace
detail
namespace
detail
{
{
// some helper classes to help create tuple result types
// some helper classes to help create tuple result types
template
<
template
<
typename
...
C
>
typename
Category
,
typename
...
C
>
struct
get_row_result
struct
get_row_result
{
{
using
category_type
=
Category
;
using
row_type
=
category_type
::
row
;
using
row_handle_type
=
row_handle
<
category_type
>
;
using
item_handle_type
=
item_handle
<
row_type
>
;
static
constexpr
size_t
N
=
sizeof
...(
C
);
static
constexpr
size_t
N
=
sizeof
...(
C
);
get_row_result
(
const
row_handle
_type
&
r
,
std
::
array
<
size_t
,
N
>
&&
columns
)
get_row_result
(
const
row_handle
&
r
,
std
::
array
<
size_t
,
N
>
&&
columns
)
:
m_row
(
r
)
:
m_row
(
r
)
,
m_columns
(
std
::
move
(
columns
))
,
m_columns
(
std
::
move
(
columns
))
{
{
}
}
const
item_handle
_type
operator
[](
size_t
ix
)
const
const
item_handle
operator
[](
size_t
ix
)
const
{
{
return
m_row
[
m_columns
[
ix
]];
return
m_row
[
m_columns
[
ix
]];
}
}
...
@@ -74,7 +63,7 @@ namespace detail
...
@@ -74,7 +63,7 @@ namespace detail
return
std
::
tuple
<
Ts
...
>
{
m_row
[
m_columns
[
Is
]].
template
as
<
Ts
>
()...};
return
std
::
tuple
<
Ts
...
>
{
m_row
[
m_columns
[
Is
]].
template
as
<
Ts
>
()...};
}
}
const
row_handle
_type
&
m_row
;
const
row_handle
&
m_row
;
std
::
array
<
size_t
,
N
>
m_columns
;
std
::
array
<
size_t
,
N
>
m_columns
;
};
};
...
@@ -112,21 +101,39 @@ auto tie(Ts &...v)
...
@@ -112,21 +101,39 @@ auto tie(Ts &...v)
}
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
/// \brief
row_handle is the way to access data in rows
/// \brief
the row class, this one is not directly accessible from the outside
template
<
typename
Category
>
class
row
class
row_handle
{
{
public
:
public
:
using
category_type
=
Category
;
row
()
=
default
;
using
row_type
=
std
::
conditional_t
<
std
::
is_const_v
<
category_type
>
,
const
typename
category_type
::
row
,
typename
category_type
::
row
>
;
using
item_handle_type
=
item_handle
<
row_handle
>
;
private
:
friend
class
item_handle
;
template
<
typename
>
template
<
typename
,
typename
...
>
friend
class
row_handle
;
friend
class
iterator_impl
;
friend
class
category
;
void
append
(
item_value
*
iv
)
{
if
(
m_head
==
nullptr
)
m_head
=
m_tail
=
iv
;
else
m_tail
=
m_tail
->
m_next
=
iv
;
}
row
*
m_next
=
nullptr
;
item_value
*
m_head
=
nullptr
,
*
m_tail
=
nullptr
;
};
template
<
typename
>
// --------------------------------------------------------------------
/// \brief row_handle is the way to access data in rows
class
row_handle
{
public
:
friend
class
item_handle
;
friend
class
item_handle
;
row_handle
()
=
default
;
row_handle
()
=
default
;
...
@@ -137,42 +144,40 @@ class row_handle
...
@@ -137,42 +144,40 @@ class row_handle
row_handle
&
operator
=
(
const
row_handle
&
)
=
default
;
row_handle
&
operator
=
(
const
row_handle
&
)
=
default
;
row_handle
&
operator
=
(
row_handle
&&
)
=
default
;
row_handle
&
operator
=
(
row_handle
&&
)
=
default
;
template
<
typename
C2
>
row_handle
(
const
category
&
cat
,
const
row
&
r
)
row_handle
(
const
row_handle
<
C2
>
&
rhs
)
:
m_category
(
const_cast
<
category
*>
(
&
cat
))
:
m_cat
(
rhs
.
m_cat
)
,
m_row
(
const_cast
<
row
*>
(
&
r
))
,
m_row
(
rhs
.
m_row
)
{
{
}
}
row_handle
(
category_type
&
cat
,
row_type
&
row
)
const
category
&
cat
()
const
:
m_cat
(
&
cat
)
,
m_row
(
&
row
)
{
{
return
*
m_category
;
}
}
explicit
operator
bool
()
const
explicit
operator
bool
()
const
{
{
return
m_cat
!=
nullptr
and
m_row
!=
nullptr
;
return
m_cat
egory
!=
nullptr
and
m_row
!=
nullptr
;
}
}
item_handle
_type
operator
[](
uint32_t
column_ix
)
item_handle
operator
[](
uint32_t
column_ix
)
{
{
return
item_handle
_type
(
column_ix
,
*
this
);
return
item_handle
(
column_ix
,
*
this
);
}
}
const
item_handle
_type
operator
[](
uint32_t
column_ix
)
const
const
item_handle
operator
[](
uint32_t
column_ix
)
const
{
{
return
item_handle
_type
(
column_ix
,
const_cast
<
row_handle
&>
(
*
this
));
return
item_handle
(
column_ix
,
const_cast
<
row_handle
&>
(
*
this
));
}
}
item_handle
_type
operator
[](
std
::
string_view
column_name
)
item_handle
operator
[](
std
::
string_view
column_name
)
{
{
return
item_handle
_type
(
add_column
(
column_name
),
*
this
);
return
item_handle
(
add_column
(
column_name
),
*
this
);
}
}
const
item_handle
_type
operator
[](
std
::
string_view
column_name
)
const
const
item_handle
operator
[](
std
::
string_view
column_name
)
const
{
{
return
item_handle
_type
(
get_column_ix
(
column_name
),
*
this
);
return
item_handle
(
get_column_ix
(
column_name
),
const_cast
<
row_handle
&>
(
*
this
)
);
}
}
template
<
typename
...
Ts
,
size_t
N
>
template
<
typename
...
Ts
,
size_t
N
>
...
@@ -183,13 +188,13 @@ class row_handle
...
@@ -183,13 +188,13 @@ class row_handle
std
::
array
<
size_t
,
N
>
cix
;
std
::
array
<
size_t
,
N
>
cix
;
for
(
size_t
i
=
0
;
i
<
N
;
++
i
)
for
(
size_t
i
=
0
;
i
<
N
;
++
i
)
cix
[
i
]
=
get_column_ix
(
columns
[
i
]);
cix
[
i
]
=
get_column_ix
(
columns
[
i
]);
return
detail
::
get_row_result
<
category_type
,
Ts
...
>
(
*
this
,
std
::
move
(
cix
));
return
detail
::
get_row_result
<
Ts
...
>
(
*
this
,
std
::
move
(
cix
));
}
}
template
<
typename
...
C
>
template
<
typename
...
C
>
auto
get
(
C
...
columns
)
const
auto
get
(
C
...
columns
)
const
{
{
return
detail
::
get_row_result
<
category_type
,
C
...
>
(
*
this
,
{
get_column_ix
(
columns
)...});
return
detail
::
get_row_result
<
C
...
>
(
*
this
,
{
get_column_ix
(
columns
)...});
}
}
void
assign
(
const
std
::
vector
<
item
>
&
values
)
void
assign
(
const
std
::
vector
<
item
>
&
values
)
...
@@ -247,32 +252,23 @@ class row_handle
...
@@ -247,32 +252,23 @@ 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
(
m_cat
->
add_column
(
name
),
value
,
updateLinked
,
validate
);
assign
(
add_column
(
name
),
value
,
updateLinked
,
validate
);
}
}
void
assign
(
size_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
)
void
assign
(
size_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
=
true
);
{
m_cat
->
update_value
(
m_row
,
column
,
value
,
updateLinked
,
validate
);
}
private
:
private
:
uint16_t
get_column_ix
(
std
::
string_view
name
)
const
uint16_t
get_column_ix
(
std
::
string_view
name
)
const
;
{
return
m_cat
->
get_column_ix
(
name
);
}
uint16_t
add_column
(
std
::
string_view
name
)
uint16_t
add_column
(
std
::
string_view
name
);
{
return
m_cat
->
add_column
(
name
);
}
void
assign
(
const
item
&
i
,
bool
updateLinked
)
void
assign
(
const
item
&
i
,
bool
updateLinked
)
{
{
assign
(
i
.
name
(),
i
.
value
(),
updateLinked
);
assign
(
i
.
name
(),
i
.
value
(),
updateLinked
);
}
}
category
_type
*
m_cat
=
nullptr
;
category
*
m_category
=
nullptr
;
row
_type
*
m_row
=
nullptr
;
row
*
m_row
=
nullptr
;
};
};
}
//
namespace
cif
::
v2
}
//
namespace
cif
::
v2
\ No newline at end of file
include/cif++/v2/validate.hpp
View file @
ab9c4d94
...
@@ -166,7 +166,7 @@ class Validator
...
@@ -166,7 +166,7 @@ class Validator
{
{
}
}
~
Validator
();
~
Validator
()
=
default
;
Validator
(
const
Validator
&
rhs
)
=
delete
;
Validator
(
const
Validator
&
rhs
)
=
delete
;
Validator
&
operator
=
(
const
Validator
&
rhs
)
=
delete
;
Validator
&
operator
=
(
const
Validator
&
rhs
)
=
delete
;
...
@@ -175,7 +175,6 @@ class Validator
...
@@ -175,7 +175,6 @@ class Validator
Validator
&
operator
=
(
Validator
&&
rhs
);
Validator
&
operator
=
(
Validator
&&
rhs
);
friend
class
dictionary_parser
;
friend
class
dictionary_parser
;
// friend class ValidatorFactory;
void
addTypeValidator
(
ValidateType
&&
v
);
void
addTypeValidator
(
ValidateType
&&
v
);
const
ValidateType
*
getValidatorForType
(
std
::
string_view
typeCode
)
const
;
const
ValidateType
*
getValidatorForType
(
std
::
string_view
typeCode
)
const
;
...
@@ -189,11 +188,11 @@ class Validator
...
@@ -189,11 +188,11 @@ class Validator
void
reportError
(
const
std
::
string
&
msg
,
bool
fatal
)
const
;
void
reportError
(
const
std
::
string
&
msg
,
bool
fatal
)
const
;
const
std
::
string
&
dictN
ame
()
const
{
return
m_name
;
}
const
std
::
string
&
n
ame
()
const
{
return
m_name
;
}
void
dictN
ame
(
const
std
::
string
&
name
)
{
m_name
=
name
;
}
void
set_n
ame
(
const
std
::
string
&
name
)
{
m_name
=
name
;
}
const
std
::
string
&
dictV
ersion
()
const
{
return
m_version
;
}
const
std
::
string
&
v
ersion
()
const
{
return
m_version
;
}
void
dictV
ersion
(
const
std
::
string
&
version
)
{
m_version
=
version
;
}
void
v
ersion
(
const
std
::
string
&
version
)
{
m_version
=
version
;
}
private
:
private
:
// name is fully qualified here:
// name is fully qualified here:
...
@@ -201,7 +200,7 @@ class Validator
...
@@ -201,7 +200,7 @@ class Validator
std
::
string
m_name
;
std
::
string
m_name
;
std
::
string
m_version
;
std
::
string
m_version
;
bool
m
S
trict
=
false
;
bool
m
_s
trict
=
false
;
std
::
set
<
ValidateType
>
mTypeValidators
;
std
::
set
<
ValidateType
>
mTypeValidators
;
std
::
set
<
ValidateCategory
>
mCategoryValidators
;
std
::
set
<
ValidateCategory
>
mCategoryValidators
;
std
::
vector
<
ValidateLink
>
mLinkValidators
;
std
::
vector
<
ValidateLink
>
mLinkValidators
;
...
...
src/v2/category.cpp
0 → 100644
View file @
ab9c4d94
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/v2/category.hpp>
namespace
cif
::
v2
{
void
category
::
update_value
(
row
*
row
,
size_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
)
{
auto
&
col
=
m_columns
[
column
];
const
char
*
oldValue
=
nullptr
;
for
(
auto
iv
=
row
->
m_head
;
iv
!=
nullptr
;
iv
=
iv
->
m_next
)
{
assert
(
iv
!=
iv
->
m_next
and
(
iv
->
m_next
==
nullptr
or
iv
!=
iv
->
m_next
->
m_next
));
if
(
iv
->
m_column_ix
==
column
)
{
oldValue
=
iv
->
c_str
();
break
;
}
}
if
(
oldValue
!=
nullptr
and
value
==
oldValue
)
// no need to update
return
;
std
::
string
oldStrValue
=
oldValue
?
oldValue
:
""
;
// // check the value
// if (col.m_validator and validate)
// (*col.m_validator)(value);
// If the field is part of the Key for this Category, remove it from the index
// before updating
bool
reinsert
=
false
;
// if (updateLinked and // an update of an Item's value
// cat->mIndex != nullptr and cat->keyFieldsByIndex().count(column))
// {
// reinsert = cat->mIndex->find(mData);
// if (reinsert)
// cat->mIndex->erase(mData);
// }
// first remove old value with cix
if
(
row
->
m_head
==
nullptr
)
;
// nothing to do
else
if
(
row
->
m_head
->
m_column_ix
==
column
)
{
auto
iv
=
row
->
m_head
;
row
->
m_head
=
iv
->
m_next
;
iv
->
m_next
=
nullptr
;
delete_item
(
iv
);
}
else
{
for
(
auto
iv
=
row
->
m_head
;
iv
->
m_next
!=
nullptr
;
iv
=
iv
->
m_next
)
{
if
(
iv
->
m_next
->
m_column_ix
!=
column
)
continue
;
auto
nv
=
iv
->
m_next
;
iv
->
m_next
=
nv
->
m_next
;
nv
->
m_next
=
nullptr
;
delete_item
(
nv
);
break
;
}
}
if
(
not
value
.
empty
())
{
auto
nv
=
create_item
(
column
,
value
);
if
(
row
->
m_head
==
nullptr
)
row
->
m_head
=
nv
;
else
{
auto
iv
=
row
->
m_head
;
while
(
iv
->
m_next
!=
nullptr
)
iv
=
iv
->
m_next
;
iv
->
m_next
=
nv
;
}
}
// if (reinsert)
// cat->mIndex->insert(mData);
// // see if we need to update any child categories that depend on this value
// auto iv = col.m_validator;
// if (not skipUpdateLinked and iv != nullptr and mCascade)
// {
// for (auto &&[childCat, linked] : cat->mChildLinks)
// {
// if (find(linked->mParentKeys.begin(), linked->mParentKeys.end(), iv->mTag) == linked->mParentKeys.end())
// continue;
// Condition cond;
// std::string childTag;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// {
// childTag = ck;
// cond = std::move(cond) && Key(ck) == oldStrValue;
// }
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond = std::move(cond) && Key(ck) == Empty();
// else
// cond = std::move(cond) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows = childCat->find(std::move(cond));
// if (rows.empty())
// continue;
// // if (cif::VERBOSE > 2)
// // {
// // std::cerr << "Parent: " << linked->mParentCategory << " Child: " << linked->mChildCategory << std::endl
// // << cond << std::endl;
// // }
// // Now, suppose there are already rows in child that conform to the new value,
// // we then skip this renam
// Condition cond_n;
// for (size_t ix = 0; ix < linked->mParentKeys.size(); ++ix)
// {
// std::string pk = linked->mParentKeys[ix];
// std::string ck = linked->mChildKeys[ix];
// // TODO add code to *NOT* test mandatory fields for Empty
// if (pk == iv->mTag)
// cond_n = std::move(cond_n) && Key(ck) == value;
// else
// {
// const char *pk_value = (*this)[pk].c_str();
// if (*pk_value == 0)
// cond_n = std::move(cond_n) && Key(ck) == Empty();
// else
// cond_n = std::move(cond_n) && ((Key(ck) == pk_value) or Key(ck) == Empty());
// }
// }
// auto rows_n = childCat->find(std::move(cond_n));
// if (not rows_n.empty())
// {
// if (cif::VERBOSE > 0)
// std::cerr << "Will not rename in child category since there are already rows that link to the parent" << std::endl;
// continue;
// }
// for (auto &cr : rows)
// cr.assign(childTag, value, false);
// }
// }
}
// proxy methods for every insertion
category
::
iterator
category
::
insert_impl
(
const_iterator
pos
,
row
*
n
)
{
assert
(
n
!=
nullptr
);
assert
(
n
->
m_next
==
nullptr
);
if
(
n
==
nullptr
)
throw
std
::
runtime_error
(
"Invalid pointer passed to insert"
);
// insert at end, most often this is the case
if
(
pos
.
m_current
==
nullptr
)
{
if
(
m_head
==
nullptr
)
m_tail
=
m_head
=
n
;
else
m_tail
=
m_tail
->
m_next
=
n
;
}
else
{
assert
(
m_head
!=
nullptr
);
if
(
pos
.
m_current
==
m_head
)
m_head
=
n
->
m_next
=
m_head
;
else
n
=
n
->
m_next
=
m_head
->
m_next
;
}
return
iterator
(
*
this
,
n
);
}
category
::
iterator
category
::
erase_impl
(
const_iterator
pos
)
{
if
(
pos
==
cend
())
return
end
();
assert
(
false
);
// TODO: implement
// row *n = const_cast<row *>(pos.row());
// row *cur;
// if (m_head == n)
// {
// m_head = static_cast<row *>(m_head->m_next);
// if (m_head == nullptr)
// m_tail = nullptr;
// n->m_next = nullptr;
// delete_row(n);
// cur = m_head;
// }
// else
// {
// cur = static_cast<row *>(n->m_next);
// if (m_tail == n)
// m_tail = static_cast<row *>(n->m_prev);
// row *p = m_head;
// while (p != nullptr and p->m_next != n)
// p = p->m_next;
// if (p != nullptr and p->m_next == n)
// {
// p->m_next = n->m_next;
// if (p->m_next != nullptr)
// p->m_next->m_prev = p;
// n->m_next = nullptr;
// }
// else
// throw std::runtime_error("remove for a row not found in the list");
// delete_row(n);
// }
// return iterator(*this, cur);
}
std
::
vector
<
std
::
string
>
get_category_fields
(
const
category
&
cat
)
{
return
{};
}
}
//
namespace
cif
::
v2
\ No newline at end of file
src/v2/dictionary_parser.cpp
View file @
ab9c4d94
...
@@ -34,23 +34,24 @@ namespace cif::v2
...
@@ -34,23 +34,24 @@ namespace cif::v2
using
namespace
literals
;
using
namespace
literals
;
class
dictionary_parser
:
public
parser_t
<>
inline
void
replace_all
(
std
::
string
&
s
,
std
::
string_view
pat
,
std
::
string_view
rep
)
{
{
public
:
for
(
std
::
string
::
size_type
i
=
s
.
find
(
pat
);
i
!=
std
::
string
::
npos
;
i
=
s
.
find
(
pat
,
i
))
using
base_type
=
parser_t
<>
;
s
.
replace
(
i
,
pat
.
size
(),
rep
.
data
(),
rep
.
size
());
using
file_type
=
typename
base_type
::
file_type
;
}
using
datablock_type
=
typename
file_type
::
datablock_type
;
using
category_type
=
typename
datablock_type
::
category_type
;
dictionary_parser
(
Validator
&
validator
,
std
::
istream
&
is
,
file_type
&
f
)
class
dictionary_parser
:
public
parser
:
base_type
(
is
,
f
)
{
public
:
dictionary_parser
(
Validator
&
validator
,
std
::
istream
&
is
,
file
&
f
)
:
parser
(
is
,
f
)
,
m_validator
(
validator
)
,
m_validator
(
validator
)
{
{
}
}
void
load_dictionary
()
void
load_dictionary
()
{
{
std
::
unique_ptr
<
datablock
_type
>
dict
;
std
::
unique_ptr
<
datablock
>
dict
;
auto
savedDatablock
=
m_datablock
;
auto
savedDatablock
=
m_datablock
;
try
try
...
@@ -65,7 +66,7 @@ class dictionary_parser : public parser_t<>
...
@@ -65,7 +66,7 @@ class dictionary_parser : public parser_t<>
default
:
default
:
{
{
dict
.
reset
(
new
datablock
_type
(
m_token_value
));
// dummy datablock, for constructing the validator only
dict
.
reset
(
new
datablock
(
m_token_value
));
// dummy datablock, for constructing the validator only
m_datablock
=
dict
.
get
();
m_datablock
=
dict
.
get
();
match
(
CIFToken
::
DATA
);
match
(
CIFToken
::
DATA
);
...
@@ -101,14 +102,14 @@ class dictionary_parser : public parser_t<>
...
@@ -101,14 +102,14 @@ class dictionary_parser : public parser_t<>
link_items
();
link_items
();
// store meta information
// store meta information
datablock
_type
::
iterator
info
;
datablock
::
iterator
info
;
bool
n
;
bool
n
;
std
::
tie
(
info
,
n
)
=
m_datablock
->
emplace
(
"dictionary"
);
std
::
tie
(
info
,
n
)
=
m_datablock
->
emplace
(
"dictionary"
);
if
(
n
)
if
(
n
)
{
{
auto
r
=
info
->
front
();
auto
r
=
info
->
front
();
m_validator
.
dictN
ame
(
r
[
"title"
].
as
<
std
::
string
>
());
m_validator
.
set_n
ame
(
r
[
"title"
].
as
<
std
::
string
>
());
m_validator
.
dictV
ersion
(
r
[
"version"
].
as
<
std
::
string
>
());
m_validator
.
v
ersion
(
r
[
"version"
].
as
<
std
::
string
>
());
}
}
m_datablock
=
savedDatablock
;
m_datablock
=
savedDatablock
;
...
@@ -129,8 +130,8 @@ class dictionary_parser : public parser_t<>
...
@@ -129,8 +130,8 @@ class dictionary_parser : public parser_t<>
bool
isCategorySaveFrame
=
m_token_value
[
0
]
!=
'_'
;
bool
isCategorySaveFrame
=
m_token_value
[
0
]
!=
'_'
;
datablock
_type
dict
(
m_token_value
);
datablock
dict
(
m_token_value
);
datablock
_type
::
iterator
cat
=
dict
.
end
();
datablock
::
iterator
cat
=
dict
.
end
();
match
(
CIFToken
::
SAVE
);
match
(
CIFToken
::
SAVE
);
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
Tag
)
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
Tag
)
...
@@ -437,14 +438,14 @@ class dictionary_parser : public parser_t<>
...
@@ -437,14 +438,14 @@ class dictionary_parser : public parser_t<>
auto
&
dict
=
*
m_datablock
;
auto
&
dict
=
*
m_datablock
;
for
(
auto
&
t
:
dict
[
"item_type_list"
])
for
(
auto
t
:
dict
[
"item_type_list"
])
{
{
std
::
string
code
,
primitiveCode
,
construct
;
std
::
string
code
,
primitiveCode
,
construct
;
cif
::
v2
::
tie
(
code
,
primitiveCode
,
construct
)
=
t
.
get
(
"code"
,
"primitive_code"
,
"construct"
);
cif
::
v2
::
tie
(
code
,
primitiveCode
,
construct
)
=
t
.
get
(
"code"
,
"primitive_code"
,
"construct"
);
ba
::
replace_all
(
construct
,
"
\\
n"
,
"
\n
"
);
replace_all
(
construct
,
"
\\
n"
,
"
\n
"
);
ba
::
replace_all
(
construct
,
"
\\
t"
,
"
\t
"
);
replace_all
(
construct
,
"
\\
t"
,
"
\t
"
);
ba
::
replace_all
(
construct
,
"
\\\n
"
,
""
);
replace_all
(
construct
,
"
\\\n
"
,
""
);
try
try
{
{
...
@@ -455,7 +456,7 @@ class dictionary_parser : public parser_t<>
...
@@ -455,7 +456,7 @@ class dictionary_parser : public parser_t<>
}
}
catch
(
const
std
::
exception
&
)
catch
(
const
std
::
exception
&
)
{
{
std
::
throw_with_nested
(
CifParserError
(
t
.
lineNr
()
,
"error in regular expression"
));
std
::
throw_with_nested
(
parse_error
(
/*t.lineNr()*/
0
,
"error in regular expression"
));
}
}
// Do not replace an already defined type validator, this won't work with pdbx_v40
// Do not replace an already defined type validator, this won't work with pdbx_v40
...
@@ -482,11 +483,12 @@ class dictionary_parser : public parser_t<>
...
@@ -482,11 +483,12 @@ class dictionary_parser : public parser_t<>
// --------------------------------------------------------------------
// --------------------------------------------------------------------
Validator
parse_dictionary
(
std
::
string_view
name
,
std
::
istream
&
is
)
;
Validator
parse_dictionary
(
std
::
string_view
name
,
std
::
istream
&
is
)
{
{
Validator
result
(
name
);
Validator
result
(
name
);
dictionary_parser
p
(
v
,
is
,
file
{});
file
f
;
dictionary_parser
p
(
result
,
is
,
f
);
p
.
load_dictionary
();
p
.
load_dictionary
();
return
result
;
return
result
;
...
...
src/v2/item.cpp
0 → 100644
View file @
ab9c4d94
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/v2/row.hpp>
namespace
cif
::
v2
{
std
::
string_view
item_handle
::
text
()
const
{
for
(
auto
iv
=
m_row_handle
.
m_row
->
m_head
;
iv
!=
nullptr
;
iv
=
iv
->
m_next
)
{
if
(
iv
->
m_column_ix
==
m_column
)
return
iv
->
text
();
}
return
{};
}
}
src/v2/parser.cpp
View file @
ab9c4d94
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cassert>
#include <iostream>
#include <map>
#include <regex>
#include <stack>
#include <cif++/CifUtils.hpp>
#include <cif++/v2/forward_decl.hpp>
#include <cif++/v2/parser.hpp>
#include <cif++/v2/file.hpp>
namespace
cif
{
extern
int
VERBOSE
;
}
namespace
cif
::
v2
{
// --------------------------------------------------------------------
sac_parser
::
sac_parser
(
std
::
istream
&
is
,
bool
init
)
:
m_source
(
is
)
{
m_validate
=
true
;
m_line_nr
=
1
;
m_bol
=
true
;
if
(
init
)
m_lookahead
=
get_next_token
();
}
// get_next_char takes a char from the buffer, or if it is empty
// from the istream. This function also does carriage/linefeed
// translation.
int
sac_parser
::
get_next_char
()
{
int
result
;
if
(
m_buffer
.
empty
())
result
=
m_source
.
get
();
else
{
result
=
m_buffer
.
top
();
m_buffer
.
pop
();
}
// very simple CR/LF translation into LF
if
(
result
==
'\r'
)
{
int
lookahead
=
m_source
.
get
();
if
(
lookahead
!=
'\n'
)
m_buffer
.
push
(
lookahead
);
result
=
'\n'
;
}
m_token_value
+=
static_cast
<
char
>
(
result
);
if
(
result
==
'\n'
)
++
m_line_nr
;
if
(
VERBOSE
>=
6
)
{
std
::
cerr
<<
"get_next_char => "
;
if
(
iscntrl
(
result
)
or
not
isprint
(
result
))
std
::
cerr
<<
int
(
result
)
<<
std
::
endl
;
else
std
::
cerr
<<
char
(
result
)
<<
std
::
endl
;
}
return
result
;
}
void
sac_parser
::
retract
()
{
assert
(
not
m_token_value
.
empty
());
char
ch
=
m_token_value
.
back
();
if
(
ch
==
'\n'
)
--
m_line_nr
;
m_buffer
.
push
(
ch
);
m_token_value
.
pop_back
();
}
int
sac_parser
::
restart
(
int
start
)
{
int
result
=
0
;
while
(
not
m_token_value
.
empty
())
retract
();
switch
(
start
)
{
case
State
:
:
Start
:
result
=
State
::
Float
;
break
;
case
State
:
:
Float
:
result
=
State
::
Int
;
break
;
case
State
:
:
Int
:
result
=
State
::
Value
;
break
;
default
:
error
(
"Invalid state in SacParser"
);
}
m_bol
=
false
;
return
result
;
}
sac_parser
::
CIFToken
sac_parser
::
get_next_token
()
{
const
auto
kEOF
=
std
::
char_traits
<
char
>::
eof
();
CIFToken
result
=
CIFToken
::
Unknown
;
int
quoteChar
=
0
;
int
state
=
State
::
Start
,
start
=
State
::
Start
;
m_bol
=
false
;
m_token_value
.
clear
();
mTokenType
=
CIFValue
::
Unknown
;
while
(
result
==
CIFToken
::
Unknown
)
{
auto
ch
=
get_next_char
();
switch
(
state
)
{
case
State
:
:
Start
:
if
(
ch
==
kEOF
)
result
=
CIFToken
::
Eof
;
else
if
(
ch
==
'\n'
)
{
m_bol
=
true
;
state
=
State
::
White
;
}
else
if
(
ch
==
' '
or
ch
==
'\t'
)
state
=
State
::
White
;
else
if
(
ch
==
'#'
)
state
=
State
::
Comment
;
else
if
(
ch
==
'_'
)
state
=
State
::
Tag
;
else
if
(
ch
==
';'
and
m_bol
)
state
=
State
::
TextField
;
else
if
(
ch
==
'\''
or
ch
==
'"'
)
{
quoteChar
=
ch
;
state
=
State
::
QuotedString
;
}
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
White
:
if
(
ch
==
kEOF
)
result
=
CIFToken
::
Eof
;
else
if
(
not
isspace
(
ch
))
{
state
=
State
::
Start
;
retract
();
m_token_value
.
clear
();
}
else
m_bol
=
(
ch
==
'\n'
);
break
;
case
State
:
:
Comment
:
if
(
ch
==
'\n'
)
{
state
=
State
::
Start
;
m_bol
=
true
;
m_token_value
.
clear
();
}
else
if
(
ch
==
kEOF
)
result
=
CIFToken
::
Eof
;
else
if
(
not
is_any_print
(
ch
))
error
(
"invalid character in comment"
);
break
;
case
State
:
:
TextField
:
if
(
ch
==
'\n'
)
state
=
State
::
TextField
+
1
;
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
else
if
(
not
is_any_print
(
ch
))
warning
(
"invalid character in text field '"
+
std
::
string
({
static_cast
<
char
>
(
ch
)})
+
"' ("
+
std
::
to_string
((
int
)
ch
)
+
")"
);
break
;
case
State
:
:
TextField
+
1
:
if
(
is_text_lead
(
ch
)
or
ch
==
' '
or
ch
==
'\t'
)
state
=
State
::
TextField
;
else
if
(
ch
==
';'
)
{
assert
(
m_token_value
.
length
()
>=
2
);
m_token_value
=
m_token_value
.
substr
(
1
,
m_token_value
.
length
()
-
3
);
mTokenType
=
CIFValue
::
TextField
;
result
=
CIFToken
::
Value
;
}
else
if
(
ch
==
kEOF
)
error
(
"unterminated textfield"
);
else
if
(
ch
!=
'\n'
)
error
(
"invalid character in text field"
);
break
;
case
State
:
:
QuotedString
:
if
(
ch
==
kEOF
)
error
(
"unterminated quoted string"
);
else
if
(
ch
==
quoteChar
)
state
=
State
::
QuotedStringQuote
;
else
if
(
not
is_any_print
(
ch
))
warning
(
"invalid character in quoted string: '"
+
std
::
string
({
static_cast
<
char
>
(
ch
)})
+
'\''
);
break
;
case
State
:
:
QuotedStringQuote
:
if
(
is_white
(
ch
))
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
String
;
if
(
m_token_value
.
length
()
<
2
)
error
(
"Invalid quoted string token"
);
m_token_value
=
m_token_value
.
substr
(
1
,
m_token_value
.
length
()
-
2
);
}
else
if
(
ch
==
quoteChar
)
;
else
if
(
is_any_print
(
ch
))
state
=
State
::
QuotedString
;
else
if
(
ch
==
kEOF
)
error
(
"unterminated quoted string"
);
else
error
(
"invalid character in quoted string"
);
break
;
case
State
:
:
Tag
:
if
(
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
Tag
;
}
break
;
case
State
:
:
Float
:
if
(
ch
==
'+'
or
ch
==
'-'
)
{
state
=
State
::
Float
+
1
;
}
else
if
(
isdigit
(
ch
))
state
=
State
::
Float
+
1
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Float
+
1
:
// if (ch == '(') // numeric???
// mState = State::NumericSuffix;
// else
if
(
ch
==
'.'
)
state
=
State
::
Float
+
2
;
else
if
(
tolower
(
ch
)
==
'e'
)
state
=
State
::
Float
+
3
;
else
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Int
;
}
else
state
=
start
=
restart
(
start
);
break
;
// parsed '.'
case
State
:
:
Float
+
2
:
if
(
tolower
(
ch
)
==
'e'
)
state
=
State
::
Float
+
3
;
else
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Float
;
}
else
state
=
start
=
restart
(
start
);
break
;
// parsed 'e'
case
State
:
:
Float
+
3
:
if
(
ch
==
'-'
or
ch
==
'+'
)
state
=
State
::
Float
+
4
;
else
if
(
isdigit
(
ch
))
state
=
State
::
Float
+
5
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Float
+
4
:
if
(
isdigit
(
ch
))
state
=
State
::
Float
+
5
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Float
+
5
:
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Float
;
}
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Int
:
if
(
isdigit
(
ch
)
or
ch
==
'+'
or
ch
==
'-'
)
state
=
State
::
Int
+
1
;
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Int
+
1
:
if
(
is_white
(
ch
)
or
ch
==
kEOF
)
{
retract
();
result
=
CIFToken
::
Value
;
mTokenType
=
CIFValue
::
Int
;
}
else
state
=
start
=
restart
(
start
);
break
;
case
State
:
:
Value
:
if
(
ch
==
'_'
)
{
std
::
string
s
=
toLowerCopy
(
m_token_value
);
if
(
s
==
"global_"
)
result
=
CIFToken
::
GLOBAL
;
else
if
(
s
==
"stop_"
)
result
=
CIFToken
::
STOP
;
else
if
(
s
==
"loop_"
)
result
=
CIFToken
::
LOOP
;
else
if
(
s
==
"data_"
)
{
state
=
State
::
DATA
;
continue
;
}
else
if
(
s
==
"save_"
)
{
state
=
State
::
SAVE
;
continue
;
}
}
if
(
result
==
CIFToken
::
Unknown
and
not
is_non_blank
(
ch
))
{
retract
();
result
=
CIFToken
::
Value
;
if
(
m_token_value
==
"."
)
mTokenType
=
CIFValue
::
Inapplicable
;
else
if
(
m_token_value
==
"?"
)
{
mTokenType
=
CIFValue
::
Unknown
;
m_token_value
.
clear
();
}
}
break
;
case
State
:
:
DATA
:
case
State
:
:
SAVE
:
if
(
not
is_non_blank
(
ch
))
{
retract
();
if
(
state
==
State
::
DATA
)
result
=
CIFToken
::
DATA
;
else
result
=
CIFToken
::
SAVE
;
m_token_value
.
erase
(
m_token_value
.
begin
(),
m_token_value
.
begin
()
+
5
);
}
break
;
default
:
assert
(
false
);
error
(
"Invalid state in get_next_token"
);
break
;
}
}
if
(
VERBOSE
>=
5
)
{
std
::
cerr
<<
get_token_name
(
result
);
if
(
mTokenType
!=
CIFValue
::
Unknown
)
std
::
cerr
<<
' '
<<
get_value_name
(
mTokenType
);
if
(
result
!=
CIFToken
::
Eof
)
std
::
cerr
<<
" "
<<
std
::
quoted
(
m_token_value
);
std
::
cerr
<<
std
::
endl
;
}
return
result
;
}
void
sac_parser
::
match
(
CIFToken
token
)
{
if
(
m_lookahead
!=
token
)
error
(
std
::
string
(
"Unexpected token, expected "
)
+
get_token_name
(
token
)
+
" but found "
+
get_token_name
(
m_lookahead
));
m_lookahead
=
get_next_token
();
}
bool
sac_parser
::
parse_single_datablock
(
const
std
::
string
&
datablock
)
{
// first locate the start, as fast as we can
auto
&
sb
=
*
m_source
.
rdbuf
();
enum
{
start
,
comment
,
string
,
string_quote
,
qstring
,
data
}
state
=
start
;
int
quote
=
0
;
bool
bol
=
true
;
std
::
string
dblk
=
"data_"
+
datablock
;
std
::
string
::
size_type
si
=
0
;
bool
found
=
false
;
for
(
auto
ch
=
sb
.
sbumpc
();
not
found
and
ch
!=
std
::
streambuf
::
traits_type
::
eof
();
ch
=
sb
.
sbumpc
())
{
switch
(
state
)
{
case
start
:
switch
(
ch
)
{
case
'#'
:
state
=
comment
;
break
;
case
'd'
:
case
'D'
:
state
=
data
;
si
=
1
;
break
;
case
'\''
:
case
'"'
:
state
=
string
;
quote
=
ch
;
break
;
case
';'
:
if
(
bol
)
state
=
qstring
;
break
;
}
break
;
case
comment
:
if
(
ch
==
'\n'
)
state
=
start
;
break
;
case
string
:
if
(
ch
==
quote
)
state
=
string_quote
;
break
;
case
string_quote
:
if
(
std
::
isspace
(
ch
))
state
=
start
;
else
state
=
string
;
break
;
case
qstring
:
if
(
ch
==
';'
and
bol
)
state
=
start
;
break
;
case
data
:
if
(
isspace
(
ch
)
and
dblk
[
si
]
==
0
)
found
=
true
;
else
if
(
dblk
[
si
++
]
!=
ch
)
state
=
start
;
break
;
}
bol
=
(
ch
==
'\n'
);
}
if
(
found
)
{
produce_datablock
(
datablock
);
m_lookahead
=
get_next_token
();
parse_datablock
();
}
return
found
;
}
sac_parser
::
datablock_index
sac_parser
::
index_datablocks
()
{
datablock_index
index
;
// first locate the start, as fast as we can
auto
&
sb
=
*
m_source
.
rdbuf
();
enum
{
start
,
comment
,
string
,
string_quote
,
qstring
,
data
,
data_name
}
state
=
start
;
int
quote
=
0
;
bool
bol
=
true
;
const
char
dblk
[]
=
"data_"
;
std
::
string
::
size_type
si
=
0
;
std
::
string
datablock
;
for
(
auto
ch
=
sb
.
sbumpc
();
ch
!=
std
::
streambuf
::
traits_type
::
eof
();
ch
=
sb
.
sbumpc
())
{
switch
(
state
)
{
case
start
:
switch
(
ch
)
{
case
'#'
:
state
=
comment
;
break
;
case
'd'
:
case
'D'
:
state
=
data
;
si
=
1
;
break
;
case
'\''
:
case
'"'
:
state
=
string
;
quote
=
ch
;
break
;
case
';'
:
if
(
bol
)
state
=
qstring
;
break
;
}
break
;
case
comment
:
if
(
ch
==
'\n'
)
state
=
start
;
break
;
case
string
:
if
(
ch
==
quote
)
state
=
string_quote
;
break
;
case
string_quote
:
if
(
std
::
isspace
(
ch
))
state
=
start
;
else
state
=
string
;
break
;
case
qstring
:
if
(
ch
==
';'
and
bol
)
state
=
start
;
break
;
case
data
:
if
(
dblk
[
si
]
==
0
and
is_non_blank
(
ch
))
{
datablock
=
{
static_cast
<
char
>
(
ch
)};
state
=
data_name
;
}
else
if
(
dblk
[
si
++
]
!=
ch
)
state
=
start
;
break
;
case
data_name
:
if
(
is_non_blank
(
ch
))
datablock
.
insert
(
datablock
.
end
(),
char
(
ch
));
else
if
(
isspace
(
ch
))
{
if
(
not
datablock
.
empty
())
index
[
datablock
]
=
m_source
.
tellg
();
state
=
start
;
}
else
state
=
start
;
break
;
}
bol
=
(
ch
==
'\n'
);
}
return
index
;
}
bool
sac_parser
::
parse_single_datablock
(
const
std
::
string
&
datablock
,
const
datablock_index
&
index
)
{
bool
result
=
false
;
auto
i
=
index
.
find
(
datablock
);
if
(
i
!=
index
.
end
())
{
m_source
.
seekg
(
i
->
second
);
produce_datablock
(
datablock
);
m_lookahead
=
get_next_token
();
parse_datablock
();
result
=
true
;
}
return
result
;
}
void
sac_parser
::
parse_file
()
{
while
(
m_lookahead
!=
CIFToken
::
Eof
)
{
switch
(
m_lookahead
)
{
case
CIFToken
:
:
GLOBAL
:
parse_global
();
break
;
case
CIFToken
:
:
DATA
:
produce_datablock
(
m_token_value
);
match
(
CIFToken
::
DATA
);
parse_datablock
();
break
;
default
:
error
(
"This file does not seem to be an mmCIF file"
);
break
;
}
}
}
void
sac_parser
::
parse_global
()
{
match
(
CIFToken
::
GLOBAL
);
while
(
m_lookahead
==
CIFToken
::
Tag
)
{
match
(
CIFToken
::
Tag
);
match
(
CIFToken
::
Value
);
}
}
void
sac_parser
::
parse_datablock
()
{
std
::
string
cat
;
while
(
m_lookahead
==
CIFToken
::
LOOP
or
m_lookahead
==
CIFToken
::
Tag
or
m_lookahead
==
CIFToken
::
SAVE
)
{
switch
(
m_lookahead
)
{
case
CIFToken
:
:
LOOP
:
{
cat
.
clear
();
// should start a new category
match
(
CIFToken
::
LOOP
);
std
::
vector
<
std
::
string
>
tags
;
while
(
m_lookahead
==
CIFToken
::
Tag
)
{
std
::
string
catName
,
itemName
;
std
::
tie
(
catName
,
itemName
)
=
splitTagName
(
m_token_value
);
if
(
cat
.
empty
())
{
produce_category
(
catName
);
cat
=
catName
;
}
else
if
(
not
iequals
(
cat
,
catName
))
error
(
"inconsistent categories in loop_"
);
tags
.
push_back
(
itemName
);
match
(
CIFToken
::
Tag
);
}
while
(
m_lookahead
==
CIFToken
::
Value
)
{
produce_row
();
for
(
auto
tag
:
tags
)
{
produce_item
(
cat
,
tag
,
m_token_value
);
match
(
CIFToken
::
Value
);
}
}
cat
.
clear
();
break
;
}
case
CIFToken
:
:
Tag
:
{
std
::
string
catName
,
itemName
;
std
::
tie
(
catName
,
itemName
)
=
splitTagName
(
m_token_value
);
if
(
not
iequals
(
cat
,
catName
))
{
produce_category
(
catName
);
cat
=
catName
;
produce_row
();
}
match
(
CIFToken
::
Tag
);
produce_item
(
cat
,
itemName
,
m_token_value
);
match
(
CIFToken
::
Value
);
break
;
}
case
CIFToken
:
:
SAVE
:
parse_save_frame
();
break
;
default
:
assert
(
false
);
break
;
}
}
}
void
sac_parser
::
parse_save_frame
()
{
error
(
"A regular CIF file should not contain a save frame"
);
}
// --------------------------------------------------------------------
void
parser
::
produce_datablock
(
const
std
::
string
&
name
)
{
const
auto
&
[
iter
,
ignore
]
=
m_file
.
emplace
(
name
);
m_datablock
=
&
(
*
iter
);
}
void
parser
::
produce_category
(
const
std
::
string
&
name
)
{
if
(
VERBOSE
>=
4
)
std
::
cerr
<<
"producing category "
<<
name
<<
std
::
endl
;
const
auto
&
[
cat
,
ignore
]
=
m_datablock
->
emplace
(
name
);
m_category
=
&*
cat
;
}
void
parser
::
produce_row
()
{
if
(
VERBOSE
>=
4
)
std
::
cerr
<<
"producing row for category "
<<
m_category
->
name
()
<<
std
::
endl
;
m_category
->
emplace
({});
m_row
=
m_category
->
back
();
// m_row.lineNr(m_line_nr);
}
void
parser
::
produce_item
(
const
std
::
string
&
category
,
const
std
::
string
&
item
,
const
std
::
string
&
value
)
{
if
(
VERBOSE
>=
4
)
std
::
cerr
<<
"producing _"
<<
category
<<
'.'
<<
item
<<
" -> "
<<
value
<<
std
::
endl
;
if
(
not
iequals
(
category
,
m_category
->
name
()))
error
(
"inconsistent categories in loop_"
);
m_row
[
item
]
=
m_token_value
;
}
}
//
namespace
cif
::
v2
\ No newline at end of file
src/v2/row.cpp
0 → 100644
View file @
ab9c4d94
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <cif++/v2/category.hpp>
namespace
cif
::
v2
{
void
row_handle
::
assign
(
size_t
column
,
std
::
string_view
value
,
bool
updateLinked
,
bool
validate
)
{
m_category
->
update_value
(
m_row
,
column
,
value
,
updateLinked
,
validate
);
}
uint16_t
row_handle
::
get_column_ix
(
std
::
string_view
name
)
const
{
return
m_category
->
get_column_ix
(
name
);
}
uint16_t
row_handle
::
add_column
(
std
::
string_view
name
)
{
return
m_category
->
add_column
(
name
);
}
}
//
namespace
cif
::
v2
\ No newline at end of file
src/v2/validate.cpp
View file @
ab9c4d94
...
@@ -24,6 +24,7 @@
...
@@ -24,6 +24,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
*/
#include <cassert>
#include <fstream>
#include <fstream>
#include <iostream>
#include <iostream>
...
@@ -217,16 +218,12 @@ const ValidateItem *ValidateCategory::getValidatorForItem(std::string_view tag)
...
@@ -217,16 +218,12 @@ const ValidateItem *ValidateCategory::getValidatorForItem(std::string_view tag)
// --------------------------------------------------------------------
// --------------------------------------------------------------------
Validator
::
Validator
(
std
::
string_view
name
,
std
::
istream
&
is
)
// Validator::Validator(std::string_view name, std::istream &is)
:
mName
(
name
)
// : mName(name)
{
// {
DictParser
p
(
*
this
,
is
);
// DictParser p(*this, is);
p
.
loadDictionary
();
// p.loadDictionary();
}
// }
Validator
::~
Validator
()
{
}
void
Validator
::
addTypeValidator
(
ValidateType
&&
v
)
void
Validator
::
addTypeValidator
(
ValidateType
&&
v
)
{
{
...
@@ -343,7 +340,7 @@ std::vector<const ValidateLink *> Validator::getLinksForChild(std::string_view c
...
@@ -343,7 +340,7 @@ std::vector<const ValidateLink *> Validator::getLinksForChild(std::string_view c
void
Validator
::
reportError
(
const
std
::
string
&
msg
,
bool
fatal
)
const
void
Validator
::
reportError
(
const
std
::
string
&
msg
,
bool
fatal
)
const
{
{
if
(
m
S
trict
or
fatal
)
if
(
m
_s
trict
or
fatal
)
throw
ValidationError
(
msg
);
throw
ValidationError
(
msg
);
else
if
(
VERBOSE
>
0
)
else
if
(
VERBOSE
>
0
)
std
::
cerr
<<
msg
<<
std
::
endl
;
std
::
cerr
<<
msg
<<
std
::
endl
;
...
@@ -357,7 +354,7 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
...
@@ -357,7 +354,7 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
for
(
auto
&
validator
:
mValidators
)
for
(
auto
&
validator
:
mValidators
)
{
{
if
(
iequals
(
validator
.
m_name
,
dictionary_name
))
if
(
iequals
(
validator
.
name
()
,
dictionary_name
))
return
validator
;
return
validator
;
}
}
...
@@ -422,12 +419,12 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
...
@@ -422,12 +419,12 @@ const Validator &ValidatorFactory::operator[](std::string_view dictionary_name)
throw
std
::
runtime_error
(
"Dictionary not found or defined ("
+
dictionary
.
string
()
+
")"
);
throw
std
::
runtime_error
(
"Dictionary not found or defined ("
+
dictionary
.
string
()
+
")"
);
}
}
assert
(
iequals
(
mValidators
.
back
().
m_name
,
dictionary_name
));
assert
(
iequals
(
mValidators
.
back
().
name
()
,
dictionary_name
));
return
mValidators
.
back
();
return
mValidators
.
back
();
}
}
void
ValiatorFactory
::
construct_validator
(
std
::
string_view
name
,
std
::
istream
&
is
)
void
Vali
d
atorFactory
::
construct_validator
(
std
::
string_view
name
,
std
::
istream
&
is
)
{
{
mValidators
.
emplace_back
(
parse_dictionary
(
name
,
is
));
mValidators
.
emplace_back
(
parse_dictionary
(
name
,
is
));
}
}
...
...
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