Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
a8e389d1
Commit
a8e389d1
authored
Feb 01, 2022
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add new COW string implementation
parent
50f36ce4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
397 additions
and
1 deletion
+397
-1
libcaf_core/CMakeLists.txt
libcaf_core/CMakeLists.txt
+1
-0
libcaf_core/caf/cow_string.hpp
libcaf_core/caf/cow_string.hpp
+296
-0
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+4
-0
libcaf_core/caf/type_id.hpp
libcaf_core/caf/type_id.hpp
+3
-1
libcaf_core/src/init_global_meta_objects.cpp
libcaf_core/src/init_global_meta_objects.cpp
+1
-0
libcaf_core/test/cow_string.cpp
libcaf_core/test/cow_string.cpp
+92
-0
No files found.
libcaf_core/CMakeLists.txt
View file @
a8e389d1
...
@@ -244,6 +244,7 @@ caf_add_component(
...
@@ -244,6 +244,7 @@ caf_add_component(
const_typed_message_view
const_typed_message_view
constructor_attach
constructor_attach
continuous_streaming
continuous_streaming
cow_string
cow_tuple
cow_tuple
decorator.sequencer
decorator.sequencer
deep_to_string
deep_to_string
...
...
libcaf_core/caf/cow_string.hpp
0 → 100644
View file @
a8e389d1
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/detail/comparable.hpp"
#include "caf/intrusive_cow_ptr.hpp"
#include "caf/make_counted.hpp"
#include "caf/ref_counted.hpp"
#include "caf/string_algorithms.hpp"
#include <string>
#include <string_view>
namespace
caf
{
/// A copy-on-write string implementation that wraps a `std::basic_string`.
template
<
class
CharT
>
class
basic_cow_string
:
detail
::
comparable
<
basic_cow_string
<
CharT
>>
,
detail
::
comparable
<
basic_cow_string
<
CharT
>
,
std
::
basic_string
<
CharT
>>
,
detail
::
comparable
<
basic_cow_string
<
CharT
>
,
const
CharT
*>
{
public:
// -- member types -----------------------------------------------------------
using
std_type
=
std
::
basic_string
<
CharT
>
;
using
view_type
=
std
::
basic_string_view
<
CharT
>
;
using
size_type
=
typename
std_type
::
size_type
;
using
const_iterator
=
typename
std_type
::
const_iterator
;
using
const_reverse_iterator
=
typename
std_type
::
const_reverse_iterator
;
// -- constants --------------------------------------------------------------
static
inline
const
size_type
npos
=
std_type
::
npos
;
// -- constructors, destructors, and assignment operators --------------------
basic_cow_string
()
{
impl_
=
make_counted
<
impl
>
();
}
explicit
basic_cow_string
(
std_type
str
)
{
impl_
=
make_counted
<
impl
>
(
std
::
move
(
str
));
}
explicit
basic_cow_string
(
view_type
str
)
{
impl_
=
make_counted
<
impl
>
(
std_type
{
str
});
}
basic_cow_string
(
basic_cow_string
&&
)
noexcept
=
default
;
basic_cow_string
(
const
basic_cow_string
&
)
noexcept
=
default
;
basic_cow_string
&
operator
=
(
basic_cow_string
&&
)
noexcept
=
default
;
basic_cow_string
&
operator
=
(
const
basic_cow_string
&
)
noexcept
=
default
;
// -- properties -------------------------------------------------------------
/// Returns a mutable reference to the managed string. Copies the string if
/// more than one reference to it exists to make sure the reference count is
/// exactly 1 when returning from this function.
std_type
&
unshared
()
{
return
impl_
.
unshared
().
str
;
}
/// Returns the managed string.
const
std_type
&
str
()
const
noexcept
{
return
impl_
->
str
;
}
/// Returns whether the reference count of the managed object is 1.
[[
nodiscard
]]
bool
unique
()
const
noexcept
{
return
impl_
->
unique
();
}
[[
nodiscard
]]
bool
empty
()
const
noexcept
{
return
impl_
->
str
.
empty
();
}
size_type
size
()
const
noexcept
{
return
impl_
->
str
.
size
();
}
size_type
length
()
const
noexcept
{
return
impl_
->
str
.
length
();
}
size_type
max_size
()
const
noexcept
{
return
impl_
->
str
.
max_size
();
}
// -- element access ---------------------------------------------------------
CharT
at
(
size_type
pos
)
const
{
return
impl_
->
str
.
at
(
pos
);
}
CharT
operator
[](
size_type
pos
)
const
{
return
impl_
->
str
[
pos
];
}
CharT
front
()
const
{
return
impl_
->
str
.
front
();
}
CharT
back
()
const
{
return
impl_
->
str
.
back
();
}
const
CharT
*
data
()
const
noexcept
{
return
impl_
->
str
.
data
();
}
const
CharT
*
c_str
()
const
noexcept
{
return
impl_
->
str
.
c_str
();
}
// -- conversion and copying -------------------------------------------------
operator
view_type
()
const
noexcept
{
return
view_type
{
impl_
->
str
};
}
basic_cow_string
substr
(
size_type
pos
=
0
,
size_type
count
=
npos
)
const
{
return
basic_cow_string
{
impl_
->
str
.
substr
(
pos
,
count
)};
}
size_type
copy
(
CharT
*
dest
,
size_type
count
,
size_type
pos
=
0
)
const
{
return
impl_
->
str
.
copy
(
dest
,
count
,
pos
);
}
// -- iterator access --------------------------------------------------------
const_iterator
begin
()
const
noexcept
{
return
impl_
->
str
.
begin
();
}
const_iterator
cbegin
()
const
noexcept
{
return
impl_
->
str
.
begin
();
}
const_reverse_iterator
rbegin
()
const
noexcept
{
return
impl_
->
str
.
rbegin
();
}
const_reverse_iterator
crbegin
()
const
noexcept
{
return
impl_
->
str
.
rbegin
();
}
const_iterator
end
()
const
noexcept
{
return
impl_
->
str
.
end
();
}
const_iterator
cend
()
const
noexcept
{
return
impl_
->
str
.
end
();
}
const_reverse_iterator
rend
()
const
noexcept
{
return
impl_
->
str
.
rend
();
}
const_reverse_iterator
crend
()
const
noexcept
{
return
impl_
->
str
.
rend
();
}
// -- predicates -------------------------------------------------------------
bool
starts_with
(
view_type
x
)
const
noexcept
{
return
caf
::
starts_with
(
impl_
->
str
,
x
);
}
bool
starts_with
(
CharT
x
)
const
noexcept
{
return
empty
()
?
false
:
front
()
==
x
;
}
bool
starts_with
(
const
CharT
*
x
)
const
{
return
starts_with
(
view_type
{
x
});
}
bool
ends_with
(
view_type
x
)
const
noexcept
{
return
caf
::
ends_with
(
impl_
->
str
,
x
);
}
bool
ends_with
(
CharT
x
)
const
noexcept
{
return
empty
()
?
false
:
back
()
==
x
;
}
bool
ends_with
(
const
CharT
*
x
)
const
{
return
ends_with
(
view_type
{
x
});
}
bool
contains
(
std
::
string_view
x
)
const
noexcept
{
return
find
(
x
)
!=
npos
;
}
bool
contains
(
char
x
)
const
noexcept
{
return
find
(
x
)
!=
npos
;
}
bool
contains
(
const
CharT
*
x
)
const
{
return
contains
(
view_type
{
x
});
}
// -- search -----------------------------------------------------------------
size_type
find
(
const
std
::
string
&
str
,
size_type
pos
=
0
)
const
noexcept
{
return
impl_
->
str
.
find
(
str
,
pos
);
}
size_type
find
(
const
basic_cow_string
&
str
,
size_type
pos
=
0
)
const
noexcept
{
return
find
(
str
.
impl_
->
str
,
pos
);
}
size_type
find
(
const
CharT
*
str
,
size_type
pos
,
size_type
count
)
const
{
return
impl_
->
str
.
find
(
str
,
pos
,
count
);
}
size_type
find
(
const
CharT
*
str
,
size_type
pos
=
0
)
const
{
return
impl_
->
str
.
find
(
str
,
pos
);
}
size_type
find
(
char
x
,
size_type
pos
=
0
)
const
noexcept
{
return
impl_
->
str
.
find
(
x
,
pos
);
}
template
<
class
T
>
std
::
enable_if_t
<
std
::
is_convertible_v
<
const
T
&
,
view_type
>
//
&&
!
std
::
is_convertible_v
<
const
T
&
,
const
CharT
*>
,
size_type
>
find
(
const
T
&
x
,
size_type
pos
=
0
)
const
noexcept
{
return
impl_
->
str
.
find
(
x
,
pos
);
}
// -- comparison -------------------------------------------------------------
int
compare
(
const
CharT
*
x
)
const
noexcept
{
return
str
().
compare
(
x
);
}
int
compare
(
const
std_type
&
x
)
const
noexcept
{
return
str
().
compare
(
x
);
}
int
compare
(
const
cow_string
&
x
)
const
noexcept
{
return
impl_
==
x
.
impl_
?
0
:
compare
(
x
.
str
());
}
// -- friends ----------------------------------------------------------------
template
<
class
Inspector
>
friend
bool
inspect
(
Inspector
&
f
,
basic_cow_string
&
x
)
{
if
constexpr
(
Inspector
::
is_loading
)
{
return
f
.
apply
(
x
.
unshared
());
}
else
{
return
f
.
apply
(
x
.
impl_
->
str
);
}
}
private:
struct
impl
:
ref_counted
{
std_type
str
;
impl
()
=
default
;
explicit
impl
(
std_type
in
)
:
str
(
std
::
move
(
in
))
{
// nop
}
impl
*
copy
()
const
{
return
new
impl
{
str
};
}
};
intrusive_cow_ptr
<
impl
>
impl_
;
};
/// A copy-on-write wrapper for a `std::string`;
/// @relates basic_cow_string
using
cow_string
=
basic_cow_string
<
char
>
;
/// A copy-on-write wrapper for a `std::string`;
/// @relates basic_cow_string
using
cow_u16string
=
basic_cow_string
<
char16_t
>
;
/// A copy-on-write wrapper for a `std::string`;
/// @relates basic_cow_string
using
cow_u32string
=
basic_cow_string
<
char32_t
>
;
}
// namespace caf
libcaf_core/caf/fwd.hpp
View file @
a8e389d1
...
@@ -17,6 +17,7 @@ namespace caf {
...
@@ -17,6 +17,7 @@ namespace caf {
// -- 1 param templates --------------------------------------------------------
// -- 1 param templates --------------------------------------------------------
template
<
class
>
class
[[
nodiscard
]]
error_code
;
template
<
class
>
class
[[
nodiscard
]]
error_code
;
template
<
class
>
class
basic_cow_string
;
template
<
class
>
class
behavior_type_of
;
template
<
class
>
class
behavior_type_of
;
template
<
class
>
class
callback
;
template
<
class
>
class
callback
;
template
<
class
>
class
dictionary
;
template
<
class
>
class
dictionary
;
...
@@ -193,6 +194,9 @@ using actor_id = uint64_t;
...
@@ -193,6 +194,9 @@ using actor_id = uint64_t;
using
byte_buffer
=
std
::
vector
<
byte
>
;
using
byte_buffer
=
std
::
vector
<
byte
>
;
using
byte_span
=
span
<
byte
>
;
using
byte_span
=
span
<
byte
>
;
using
const_byte_span
=
span
<
const
byte
>
;
using
const_byte_span
=
span
<
const
byte
>
;
using
cow_string
=
basic_cow_string
<
char
>
;
using
cow_u16string
=
basic_cow_string
<
char16_t
>
;
using
cow_u32string
=
basic_cow_string
<
char32_t
>
;
using
ip_address
=
ipv6_address
;
using
ip_address
=
ipv6_address
;
using
ip_endpoint
=
ipv6_endpoint
;
using
ip_endpoint
=
ipv6_endpoint
;
using
ip_subnet
=
ipv6_subnet
;
using
ip_subnet
=
ipv6_subnet
;
...
...
libcaf_core/caf/type_id.hpp
View file @
a8e389d1
...
@@ -374,12 +374,14 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
...
@@ -374,12 +374,14 @@ CAF_BEGIN_TYPE_ID_BLOCK(core_module, 0)
CAF_ADD_TYPE_ID
(
core_module
,
(
std
::
set
<
std
::
string
>
)
)
CAF_ADD_TYPE_ID
(
core_module
,
(
std
::
set
<
std
::
string
>
)
)
// -- CAF types
// -- CAF types
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
action
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
action
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
actor
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
actor
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
actor_addr
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
actor_addr
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
byte_buffer
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
byte_buffer
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
config_value
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
config_value
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
cow_string
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
cow_u16string
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
cow_u32string
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
dictionary
<
caf
::
config_value
>
)
)
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
dictionary
<
caf
::
config_value
>
)
)
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
down_msg
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
down_msg
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
downstream_msg
))
CAF_ADD_TYPE_ID
(
core_module
,
(
caf
::
downstream_msg
))
...
...
libcaf_core/src/init_global_meta_objects.cpp
View file @
a8e389d1
...
@@ -12,6 +12,7 @@
...
@@ -12,6 +12,7 @@
#include "caf/byte_buffer.hpp"
#include "caf/byte_buffer.hpp"
#include "caf/callback.hpp"
#include "caf/callback.hpp"
#include "caf/config_value.hpp"
#include "caf/config_value.hpp"
#include "caf/cow_string.hpp"
#include "caf/downstream_msg.hpp"
#include "caf/downstream_msg.hpp"
#include "caf/error.hpp"
#include "caf/error.hpp"
#include "caf/group.hpp"
#include "caf/group.hpp"
...
...
libcaf_core/test/cow_string.cpp
0 → 100644
View file @
a8e389d1
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#define CAF_SUITE cow_string
#include "caf/cow_string.hpp"
#include "core-test.hpp"
using
std
::
make_tuple
;
using
std
::
string
;
using
std
::
tuple
;
using
namespace
caf
;
using
namespace
std
::
literals
;
SCENARIO
(
"default constructed COW strings are empty"
)
{
WHEN
(
"default-constructing a COW tuple"
)
{
cow_string
str
;
THEN
(
"the string is empty"
)
{
CHECK
(
str
.
empty
());
CHECK_EQ
(
str
.
size
(),
0u
);
CHECK_EQ
(
str
.
length
(),
0u
);
CHECK_EQ
(
str
.
begin
(),
str
.
end
());
CHECK_EQ
(
str
.
rbegin
(),
str
.
rend
());
}
AND
(
"the reference count is exactly 1"
)
{
CHECK
(
str
.
unique
());
}
}
}
SCENARIO
(
"COW string are constructible from STD strings"
)
{
WHEN
(
"copy-constructing a COW string from an STD string"
)
{
auto
std_str
=
"hello world"
s
;
auto
str
=
cow_string
{
std_str
};
THEN
(
"the COW string contains a copy of the original string content"
)
{
CHECK
(
!
str
.
empty
());
CHECK_EQ
(
str
.
size
(),
std_str
.
size
());
CHECK_EQ
(
str
.
length
(),
std_str
.
length
());
CHECK_NE
(
str
.
begin
(),
str
.
end
());
CHECK_NE
(
str
.
rbegin
(),
str
.
rend
());
CHECK_EQ
(
str
,
std_str
);
}
AND
(
"the reference count is exactly 1"
)
{
CHECK
(
str
.
unique
());
}
}
WHEN
(
"move-constructing a COW string from an STD string"
)
{
auto
std_str
=
"hello world"
s
;
auto
str
=
cow_string
{
std
::
move
(
std_str
)};
THEN
(
"the COW string contains the original string content"
)
{
CHECK
(
!
str
.
empty
());
CHECK_NE
(
str
.
begin
(),
str
.
end
());
CHECK_NE
(
str
.
rbegin
(),
str
.
rend
());
CHECK_NE
(
str
,
std_str
);
CHECK_EQ
(
str
,
"hello world"
);
}
AND
(
"the reference count is exactly 1"
)
{
CHECK
(
str
.
unique
());
}
}
}
SCENARIO
(
"copying COW strings makes shallow copies"
)
{
WHEN
(
"copy-constructing a COW string from an another COW string"
)
{
auto
str1
=
cow_string
{
"hello world"
s
};
auto
str2
=
str1
;
THEN
(
"both COW strings point to the same data"
)
{
CHECK_EQ
(
str1
.
data
(),
str2
.
data
());
}
AND
(
"the reference count is at least 2"
)
{
CHECK
(
!
str1
.
unique
());
CHECK
(
!
str2
.
unique
());
}
}
}
SCENARIO
(
"COW strings detach their content when becoming unshared"
)
{
WHEN
(
"copy-constructing a COW string from an another COW string"
)
{
auto
str1
=
cow_string
{
"hello world"
s
};
auto
str2
=
str1
;
THEN
(
"writing to the original does not change the copy"
)
{
str1
.
unshared
()
=
"foobar"
;
CHECK_EQ
(
str1
,
"foobar"
);
CHECK_EQ
(
str2
,
"hello world"
);
CHECK
(
str1
.
unique
());
CHECK
(
str2
.
unique
());
}
}
}
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